auster 0.2.2

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 +7 -0
  2. data/.editorconfig +13 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +41 -0
  6. data/.travis.yml +5 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +152 -0
  11. data/Rakefile +6 -0
  12. data/auster.gemspec +37 -0
  13. data/bin/auster +8 -0
  14. data/bin/console +8 -0
  15. data/example-repo/.auster.yaml +0 -0
  16. data/example-repo/cfer-helpers/.keep +0 -0
  17. data/example-repo/config/.keep +0 -0
  18. data/example-repo/config/schema.yaml +10 -0
  19. data/example-repo/config/us-west-2/dev-ed1.yaml +7 -0
  20. data/example-repo/config/validator.rb +5 -0
  21. data/example-repo/steps/.keep +0 -0
  22. data/example-repo/steps/00.bootstrap/.keep +0 -0
  23. data/example-repo/steps/00.bootstrap/cfer/defs/s3.rb +3 -0
  24. data/example-repo/steps/00.bootstrap/cfer/outputs.rb +1 -0
  25. data/example-repo/steps/00.bootstrap/cfer/parameters.rb +0 -0
  26. data/example-repo/steps/00.bootstrap/cfer/require.rb +0 -0
  27. data/example-repo/steps/00.bootstrap/on-create.d/00-debug.rb +4 -0
  28. data/example-repo/steps/00.bootstrap/on-destroy.d/00-debug.rb +4 -0
  29. data/example-repo/steps/00.bootstrap/post-converge.d/00-debug.rb +5 -0
  30. data/example-repo/steps/00.bootstrap/pre-converge.d/00-debug.rb +4 -0
  31. data/example-repo/steps/01.dependent/.keep +0 -0
  32. data/example-repo/steps/01.dependent/cfer/defs/s3.rb +3 -0
  33. data/example-repo/steps/01.dependent/cfer/outputs.rb +1 -0
  34. data/example-repo/steps/01.dependent/cfer/parameters.rb +0 -0
  35. data/example-repo/steps/01.dependent/cfer/require.rb +0 -0
  36. data/example-repo/steps/01.dependent/on-create.d/00-debug.rb +4 -0
  37. data/example-repo/steps/01.dependent/on-destroy.d/00-debug.rb +4 -0
  38. data/example-repo/steps/01.dependent/post-converge.d/00-debug.rb +7 -0
  39. data/example-repo/steps/01.dependent/pre-converge.d/00-debug.rb +5 -0
  40. data/lib/cfer/auster/cfer_evaluator.rb +125 -0
  41. data/lib/cfer/auster/cfer_helpers.rb +71 -0
  42. data/lib/cfer/auster/cli/_shared.rb +49 -0
  43. data/lib/cfer/auster/cli/destroy.rb +34 -0
  44. data/lib/cfer/auster/cli/generate/repo.rb +27 -0
  45. data/lib/cfer/auster/cli/generate/step.rb +27 -0
  46. data/lib/cfer/auster/cli/generate.rb +35 -0
  47. data/lib/cfer/auster/cli/json.rb +44 -0
  48. data/lib/cfer/auster/cli/nuke.rb +62 -0
  49. data/lib/cfer/auster/cli/run.rb +34 -0
  50. data/lib/cfer/auster/cli.rb +60 -0
  51. data/lib/cfer/auster/config.rb +70 -0
  52. data/lib/cfer/auster/logging.rb +32 -0
  53. data/lib/cfer/auster/param_validator.rb +22 -0
  54. data/lib/cfer/auster/repo.rb +158 -0
  55. data/lib/cfer/auster/script_executor.rb +57 -0
  56. data/lib/cfer/auster/step.rb +181 -0
  57. data/lib/cfer/auster/version.rb +5 -0
  58. data/lib/cfer/auster.rb +22 -0
  59. metadata +270 -0
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cfer"
4
+
5
+ module Cfer
6
+ module Core
7
+ class Resource
8
+ # TODO: we need a better way to inject general helpers.
9
+
10
+ def cfize(text, capture_regexp: nil)
11
+ Cfer::Auster::CferHelpers.cfize(text, capture_regexp: capture_regexp)
12
+ end
13
+ end
14
+ end
15
+
16
+ module Auster
17
+ class CloudFormationError < RuntimeError; end
18
+
19
+ class CferEvaluator
20
+ include Cfer::Auster::Logging::Mixin
21
+
22
+ def initialize(path:, stack_name:, parameters:, metadata:, client_options: {}, stack_options: {})
23
+ raise "path must be a String" unless path.is_a?(String)
24
+ raise "path must be a directory" unless File.directory?(path)
25
+
26
+ raise "stack_name must be a String" unless stack_name.is_a?(String)
27
+
28
+ raise "parameters must be a Hash" unless parameters.is_a?(Hash)
29
+
30
+ parameters[:AusterOptions] ||= {}
31
+
32
+ @stack_name = stack_name
33
+ @stack_options = stack_options
34
+ @cfer_client = Cfer::Cfn::Client.new(client_options.merge(stack_name: stack_name, region: parameters[:AWSRegion]))
35
+ @cfer_stack = Cfer::Core::Stack.new(
36
+ stack_options.merge(
37
+ client: @cfer_client, include_base: path, parameters: parameters,
38
+ force_s3: !!parameters[:AusterOptions][:S3Path],
39
+ s3_path: parameters[:AusterOptions][:S3Path]
40
+ )
41
+ )
42
+
43
+ require_rb = File.join(path, "require.rb")
44
+ parameters_rb = File.join(path, "parameters.rb")
45
+ outputs_rb = File.join(path, "outputs.rb")
46
+
47
+ global_helpers_dir = File.join(path, "../../../cfer-helpers")
48
+ global_helpers = Dir["#{global_helpers_dir}/**/*.rb"].reject { |f| File.basename(f).start_with?("_") }
49
+ helpers_dir = File.join(path, "helpers")
50
+ helpers = Dir["#{helpers_dir}/**/*.rb"].reject { |f| File.basename(f).start_with?("_") }
51
+ defs_dir = File.join(path, "defs")
52
+
53
+ @cfer_stack.extend Cfer::Auster::CferHelpers
54
+ @cfer_stack.build_from_block do
55
+ self[:Metadata][:Auster] = metadata
56
+
57
+ global_helpers.each do |helper_file|
58
+ eval_file helper_file
59
+ end
60
+
61
+ helpers.each do |helper_file|
62
+ eval_file helper_file
63
+ end
64
+
65
+ [require_rb, parameters_rb, outputs_rb].each do |file|
66
+ f = file.gsub(path, ".")
67
+ include_template f if File.file?(file)
68
+ end
69
+
70
+ Dir["#{defs_dir}/**/*.rb"].each do |def_file|
71
+ f = def_file.gsub(path, ".")
72
+ include_template f
73
+ end
74
+ end
75
+ end
76
+
77
+ def converge!(block: true)
78
+ # because it isn't actually redundant...
79
+ # rubocop:disable Style/RedundantBegin
80
+ begin
81
+ @cfer_stack.converge!(@stack_options)
82
+ tail! if block
83
+ rescue Aws::CloudFormation::Errors::ValidationError => err
84
+ if err.message == "No updates are to be performed."
85
+ logger.info "CloudFormation has no updates to perform."
86
+ else
87
+ logger.error "Error (#{err.class.name}) in converge: #{err.message}"
88
+ raise err
89
+ end
90
+ end
91
+ end
92
+
93
+ def destroy!(block: true)
94
+ @cfer_client.delete_stack(stack_name: @stack_name)
95
+ tail! if block
96
+ end
97
+
98
+ def tail!(throw_if_failed: true)
99
+ tail_start = DateTime.now
100
+ has_shown_bar = false
101
+ has_failed = false
102
+
103
+ @cfer_client.tail(number: 0, follow: true) do |event|
104
+ has_failed = true if event.timestamp >= tail_start && event.resource_status.include?("FAILED")
105
+ if event.timestamp >= tail_start && !has_shown_bar
106
+ logger.info "CFN >> ----- CURRENT RUN START -----"
107
+ has_failed = false
108
+ has_shown_bar = true
109
+ end
110
+ logger.info "CFN >> %-30s %-40s %-20s %s" % [
111
+ event.resource_status, event.resource_type,
112
+ event.logical_resource_id, event.resource_status_reason
113
+ ]
114
+ end
115
+
116
+ raise "Operation failed. Please check the log." if has_failed && throw_if_failed
117
+ nil
118
+ end
119
+
120
+ def generate_json
121
+ JSON.pretty_generate(@cfer_stack)
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,71 @@
1
+ module Cfer
2
+ module Auster
3
+ module CferHelpers
4
+ CFIZER_DEFAULT_CAPTURE_REGEXP = /C\{(?<directive>.*?)\}/
5
+
6
+ def eval_file(filename)
7
+ instance_eval IO.read(filename), filename
8
+ end
9
+
10
+ def import(name)
11
+ { "Fn::ImportValue" => _exported_name(name) }
12
+ end
13
+
14
+ def export(name, value)
15
+ output name, value, Export: { Name: _exported_name(name) }
16
+ end
17
+
18
+ def _exported_name(name)
19
+ "#{parameters[:PlanID]}--#{name}"
20
+ end
21
+
22
+ def cfize(text, capture_regexp: nil)
23
+ CferHelpers.cfize(text, capture_regexp: capture_regexp)
24
+ end
25
+
26
+ def self.cfize(text, capture_regexp: nil)
27
+ raise "'text' must be a string." unless text.is_a?(String)
28
+
29
+ capture_regexp ||= CFIZER_DEFAULT_CAPTURE_REGEXP
30
+
31
+ raise "'capture_regexp' must be a Regexp." unless capture_regexp.is_a?(Regexp)
32
+ raise "'capture_regexp' must include a 'contents' named 'directive'." \
33
+ unless capture_regexp.named_captures.key?("directive")
34
+
35
+ working = []
36
+ until working[-2] == "" && working[-1] == "" do
37
+ if working.empty?
38
+ working = text.partition(capture_regexp)
39
+ else
40
+ working[-1] = working[-1].partition(capture_regexp)
41
+ working = working.flatten
42
+ end
43
+ end
44
+
45
+ cfizer = Cfizer.new
46
+ Cfizer::Fn.join("", working.map do |token|
47
+ match = capture_regexp.match(token)
48
+ if match.nil?
49
+ token
50
+ else
51
+ cfizer.cfize(match["directive"])
52
+ end
53
+ end.reject { |t| t == ""})
54
+ end
55
+
56
+ class Cfizer
57
+ begin
58
+ include Cfer::Core::Functions
59
+ rescue NameError => _
60
+ # we need to fall back to the old Cfer setup
61
+ include Cfer::Core
62
+ include Cfer::Cfn
63
+ end
64
+
65
+ def cfize(directive)
66
+ instance_eval directive
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+ require "logger"
4
+
5
+ module Cfer
6
+ module Auster
7
+ module CLI
8
+ def self.base_options(cmd)
9
+ cmd.instance_eval do
10
+ flag :v, :verbose, "sets logging to DEBUG" do |_, _|
11
+ Cfer::Auster::Logging.logger.level = Logger::DEBUG
12
+ end
13
+ end
14
+ end
15
+
16
+ def self.standard_options(cmd)
17
+ cmd.instance_eval do
18
+ CLI.base_options(cmd)
19
+
20
+ flag :h, :help, "show help for this command" do |_, cmd|
21
+ puts cmd.help
22
+ Kernel.exit 0
23
+ end
24
+
25
+ option :l, :"log-level",
26
+ "Configures the verbosity of the Auster and Cfer loggers. (default: info)",
27
+ argument: :required
28
+
29
+ option :p, :"plan-path",
30
+ "The path to the Auster plan repo that should be used (otherwise searches from pwd)",
31
+ argument: :required
32
+ end
33
+ end
34
+
35
+ def self.repo_from_options(opts, &block)
36
+ require "cfer/auster/repo"
37
+
38
+ repo =
39
+ if opts[:"plan-path"]
40
+ Cfer::Auster::Repo.new(opts[:"plan-path"])
41
+ else
42
+ Cfer::Auster::Repo.discover_from_cwd
43
+ end
44
+
45
+ block.call(repo)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ require "cfer/auster/cli/_shared"
5
+
6
+ module Cfer
7
+ module Auster
8
+ module CLI
9
+ def self.destroy
10
+ Cri::Command.define do
11
+ name "destroy"
12
+ usage "destroy aws-region/config-set count-or-tag"
13
+ description "Destroys this Auster step in your AWS account."
14
+
15
+ CLI.standard_options(self)
16
+
17
+ run do |opts, args, cmd|
18
+ if args.length < 2
19
+ puts cmd.help
20
+ exit 1
21
+ else
22
+ CLI.repo_from_options(opts) do |repo|
23
+ config_set = repo.config_set(args[0])
24
+ step = repo.step_by_count_or_tag(args[1])
25
+
26
+ step.destroy(config_set)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ module Cfer
5
+ module Auster
6
+ module CLI
7
+ def self.generate_repo
8
+ Cri::Command.define do
9
+ name "repo"
10
+ usage "repo OUTPUT_PATH"
11
+ description "Generates a new Auster plan repo."
12
+
13
+ CLI.base_options(self)
14
+
15
+ flag :h, :help, "show help for this command" do |_, cmd|
16
+ puts cmd.help
17
+ Kernel.exit 0
18
+ end
19
+
20
+ run do |_, _, cmd|
21
+ raise "TODO: implement"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ module Cfer
5
+ module Auster
6
+ module CLI
7
+ def self.generate_step
8
+ Cri::Command.define do
9
+ name "step"
10
+ usage "step ##"
11
+ description "Generates a step in the current Auster repo."
12
+
13
+ CLI.base_options(self)
14
+
15
+ flag :h, :help, "show help for this command" do |_, cmd|
16
+ puts cmd.help
17
+ Kernel.exit 0
18
+ end
19
+
20
+ run do |_, _, cmd|
21
+ raise "TODO: implement"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ require "cfer/auster/cli/generate/repo"
5
+ require "cfer/auster/cli/generate/step"
6
+
7
+ module Cfer
8
+ module Auster
9
+ module CLI
10
+ def self.generate
11
+ ret = Cri::Command.define do
12
+ name "generate"
13
+ description "Encapsulates generators for Auster."
14
+
15
+ CLI.base_options(self)
16
+
17
+ flag :h, :help, "show help for this command" do |_, cmd|
18
+ puts cmd.help
19
+ Kernel.exit 0
20
+ end
21
+
22
+ run do |_, _, cmd|
23
+ puts cmd.help
24
+ Kernel.exit 0
25
+ end
26
+ end
27
+
28
+ ret.add_command(CLI.generate_repo)
29
+ ret.add_command(CLI.generate_step)
30
+
31
+ ret
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ require "cfer/auster/cli/_shared"
5
+
6
+ module Cfer
7
+ module Auster
8
+ module CLI
9
+ def self.json
10
+ Cri::Command.define do
11
+ name "json"
12
+ usage "json aws-region/config-set count-or-tag"
13
+ description "Generates the CloudFormation JSON for this step."
14
+
15
+ CLI.standard_options(self)
16
+
17
+ option :o, :"output-file",
18
+ "Saves the JSON output to a file (otherwise prints to stdout)",
19
+ argument: :required
20
+
21
+ run do |opts, args, cmd|
22
+ if args.length < 2
23
+ puts cmd.help
24
+ exit 1
25
+ else
26
+ CLI.repo_from_options(opts) do |repo|
27
+ config_set = repo.config_set(args[0])
28
+ step = repo.step_by_count_or_tag(args[1])
29
+
30
+ ret = step.json(config_set)
31
+
32
+ if opts[:"output-file"]
33
+ IO.write(opts[:"output-file"], ret)
34
+ else
35
+ puts ret
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ require "cfer/auster/cli/_shared"
5
+
6
+ module Cfer
7
+ module Auster
8
+ module CLI
9
+ def self.nuke
10
+ Cri::Command.define do
11
+ extend Cfer::Auster::Logging::Mixin
12
+
13
+ name "nuke"
14
+ usage "nuke aws-region/config-set"
15
+ description "Destroys ALL AWS RESOURCES related to this config set."
16
+
17
+ CLI.standard_options(self)
18
+
19
+ flag nil, :force, "bypasses confirmation - use with care!"
20
+
21
+ run do |opts, args, cmd|
22
+ if args.length < 1
23
+ puts cmd.help
24
+ exit 1
25
+ else
26
+ CLI.repo_from_options(opts) do |repo|
27
+ config_set = repo.config_set(args[0])
28
+
29
+ accepted = !!opts[:force]
30
+
31
+ if !accepted && $stdin.tty?
32
+ $stderr.write "\n\n"
33
+ $stderr.write "!!! YOU ARE ABOUT TO DO SOMETHING VERY DRASTIC! !!!\n"
34
+ $stderr.write "You are requesting to destroy ALL STEPS of the config set '#{config_set.full_name}'.\n"
35
+ $stderr.write "If you are certain you wish to do this, please type CONFIRM: "
36
+
37
+ input = $stdin.readline.chomp
38
+
39
+ if input != "CONFIRM"
40
+ $stderr.write "\n\nInvalid input. Aborting nuke.\n\n"
41
+ Kernel.exit 1
42
+ end
43
+
44
+ accepted = true
45
+ end
46
+
47
+ unless accepted
48
+ logger.error "You must pass interactive confirmation or use the --force parameter to nuke."
49
+ Kernel.exit 1
50
+ end
51
+
52
+ repo.nuke(config_set)
53
+
54
+ logger.warn "I really, really hope you meant to do that."
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+
4
+ require "cfer/auster/cli/_shared"
5
+
6
+ module Cfer
7
+ module Auster
8
+ module CLI
9
+ def self.run
10
+ Cri::Command.define do
11
+ name "run"
12
+ usage "run aws-region/config-set count-or-tag"
13
+ description "Runs this Auster step against your AWS infrastructure."
14
+
15
+ CLI.standard_options(self)
16
+
17
+ run do |opts, args, cmd|
18
+ if args.length < 2
19
+ puts cmd.help
20
+ exit 1
21
+ else
22
+ CLI.repo_from_options(opts) do |repo|
23
+ config_set = repo.config_set(args[0])
24
+ step = repo.step_by_count_or_tag(args[1])
25
+
26
+ step.run(config_set)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+ require "cri"
3
+ require "semantic"
4
+ require "json"
5
+
6
+ require "cfer/auster"
7
+ require "cfer/auster/cli/_shared"
8
+ require "cfer/auster/cli/generate"
9
+ require "cfer/auster/cli/json"
10
+ require "cfer/auster/cli/run"
11
+ require "cfer/auster/cli/destroy"
12
+ require "cfer/auster/cli/nuke"
13
+
14
+ module Cfer
15
+ module Auster
16
+ module CLI
17
+ def self.root
18
+ ret = Cri::Command.define do
19
+ name "auster"
20
+ description "The best way to manage CloudFormation. Ever. (We think.)"
21
+
22
+ CLI.base_options(self)
23
+
24
+ flag :h, :help, "show help for this command" do |_, cmd|
25
+ puts cmd.help
26
+ Kernel.exit 0
27
+ end
28
+
29
+ flag nil, :version, "show version information for this command" do |_, _|
30
+ puts Cfer::Auster::VERSION
31
+ Kernel.exit 0
32
+ end
33
+ flag nil, :"version-json", "show version information for this command in JSON" do |_, _|
34
+ puts JSON.pretty_generate(
35
+ Semantic::Version.new(Cfer::Auster::VERSION).to_h.reject { |_, v| v.nil? }
36
+ )
37
+ Kernel.exit 0
38
+ end
39
+
40
+ run do |_, _, cmd|
41
+ puts cmd.help
42
+ Kernel.exit 0
43
+ end
44
+ end
45
+
46
+ ret.add_command(CLI.generate)
47
+ ret.add_command(CLI.json)
48
+ ret.add_command(CLI.run)
49
+ ret.add_command(CLI.destroy)
50
+ ret.add_command(CLI.nuke)
51
+
52
+ ret
53
+ end
54
+
55
+ def self.execute(args)
56
+ CLI.root.run(args)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+ require "kwalify"
3
+
4
+ module Cfer
5
+ module Auster
6
+ class Config
7
+ include Cfer::Auster::Logging::Mixin
8
+
9
+ attr_reader :name
10
+ attr_reader :aws_region
11
+ attr_reader :data
12
+
13
+ def initialize(name:, aws_region:, data:)
14
+ raise "name must be a String" unless name.is_a?(String)
15
+ raise "aws_region must be a String" unless aws_region.is_a?(String)
16
+ raise "data must be a Hash" unless data.is_a?(Hash)
17
+
18
+ @name = name.dup.freeze
19
+ @aws_region = aws_region.dup.freeze
20
+ @data = data.deep_symbolize_keys
21
+
22
+ @data[:PlanID] = @name
23
+ @data[:AWSRegion] = @aws_region
24
+
25
+ IceNine.deep_freeze(@data)
26
+ end
27
+
28
+ def full_name
29
+ "#{aws_region}/#{name}"
30
+ end
31
+
32
+ def env_vars_for_shell
33
+ {
34
+ "PLAN_ID" => name,
35
+ "AWS_REGION" => aws_region,
36
+ "AWS_DEFAULT_REGION" => aws_region
37
+ }
38
+ end
39
+
40
+ class << self
41
+ include Cfer::Auster::Logging::Mixin
42
+
43
+ def from_file(name:, aws_region:, data_file:, schema_file:)
44
+ logger.debug "Loading config set from #{data_file}"
45
+ schema = schema_file.nil? ? nil : Kwalify::Yaml.load_file(schema_file)
46
+ validator = schema.nil? ? nil : Kwalify::Validator.new(schema)
47
+
48
+ parser = Kwalify::Yaml::Parser.new(validator)
49
+
50
+ data = parser.parse_file(data_file)
51
+ errors = parser.errors()
52
+
53
+ if errors && !errors.empty?
54
+ # TODO: make a better error to raise that can encapsulate these validation failures.
55
+ msg = "Schema validation failed for #{data_file}."
56
+
57
+ logger.error "Schema validation failed for #{data_file}."
58
+ errors.each do |e|
59
+ logger.error "#{e.linenum}:#{e.column} [#{e.path}] #{e.message}"
60
+ end
61
+
62
+ raise msg
63
+ end
64
+
65
+ Config.new(name: name, aws_region: aws_region, data: data)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module Cfer
6
+ module Auster
7
+ module Logging
8
+ def self.logger
9
+ @logger
10
+ end
11
+
12
+ def self.logdev
13
+ @logdev
14
+ end
15
+
16
+ # rubocop:disable Style/AccessorMethodName
17
+ def self.set_logdev(logdev)
18
+ @logdev = logdev
19
+ @logger = Logger.new(@logdev)
20
+ end
21
+
22
+ set_logdev($stderr)
23
+ @logger.level = Logger::INFO
24
+
25
+ module Mixin
26
+ def logger
27
+ Cfer::Auster::Logging.logger
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cfer
4
+ module Auster
5
+ class ParamValidator
6
+ def initialize(&validator)
7
+ raise "validator must be a Proc." unless validator.is_a?(Proc)
8
+ raise "validator must be arity 2." unless validator.arity == 2
9
+
10
+ @validator = validator
11
+ end
12
+
13
+ def validate(parameters)
14
+ raise "parameters must be a Hash." unless parameters.is_a?(Hash)
15
+
16
+ errors = []
17
+ @validator.call(parameters, errors)
18
+ errors
19
+ end
20
+ end
21
+ end
22
+ end