simplygenius-atmos 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/exe/atmos +2 -2
  4. data/lib/{atmos.rb → simplygenius/atmos.rb} +9 -7
  5. data/lib/simplygenius/atmos/cli.rb +116 -0
  6. data/lib/simplygenius/atmos/commands/account.rb +69 -0
  7. data/lib/simplygenius/atmos/commands/apply.rb +24 -0
  8. data/lib/simplygenius/atmos/commands/auth_exec.rb +34 -0
  9. data/lib/simplygenius/atmos/commands/base_command.rb +16 -0
  10. data/lib/simplygenius/atmos/commands/bootstrap.rb +76 -0
  11. data/lib/simplygenius/atmos/commands/container.rb +62 -0
  12. data/lib/simplygenius/atmos/commands/destroy.rb +22 -0
  13. data/lib/simplygenius/atmos/commands/generate.rb +187 -0
  14. data/lib/simplygenius/atmos/commands/init.rb +22 -0
  15. data/lib/simplygenius/atmos/commands/new.rb +22 -0
  16. data/lib/simplygenius/atmos/commands/otp.rb +58 -0
  17. data/lib/simplygenius/atmos/commands/plan.rb +24 -0
  18. data/lib/simplygenius/atmos/commands/secret.rb +91 -0
  19. data/lib/simplygenius/atmos/commands/terraform.rb +56 -0
  20. data/lib/simplygenius/atmos/commands/user.rb +78 -0
  21. data/lib/simplygenius/atmos/config.rb +279 -0
  22. data/lib/simplygenius/atmos/exceptions.rb +13 -0
  23. data/lib/simplygenius/atmos/generator.rb +232 -0
  24. data/lib/simplygenius/atmos/ipc.rb +136 -0
  25. data/lib/simplygenius/atmos/ipc_actions/notify.rb +31 -0
  26. data/lib/simplygenius/atmos/ipc_actions/ping.rb +23 -0
  27. data/lib/simplygenius/atmos/logging.rb +164 -0
  28. data/lib/simplygenius/atmos/otp.rb +62 -0
  29. data/lib/simplygenius/atmos/plugin.rb +27 -0
  30. data/lib/simplygenius/atmos/plugin_manager.rb +120 -0
  31. data/lib/simplygenius/atmos/plugins/output_filter.rb +29 -0
  32. data/lib/simplygenius/atmos/plugins/prompt_notify.rb +21 -0
  33. data/lib/simplygenius/atmos/provider_factory.rb +23 -0
  34. data/lib/simplygenius/atmos/providers/aws/account_manager.rb +83 -0
  35. data/lib/simplygenius/atmos/providers/aws/auth_manager.rb +220 -0
  36. data/lib/simplygenius/atmos/providers/aws/container_manager.rb +118 -0
  37. data/lib/simplygenius/atmos/providers/aws/provider.rb +53 -0
  38. data/lib/simplygenius/atmos/providers/aws/s3_secret_manager.rb +51 -0
  39. data/lib/simplygenius/atmos/providers/aws/user_manager.rb +213 -0
  40. data/lib/simplygenius/atmos/settings_hash.rb +93 -0
  41. data/lib/simplygenius/atmos/source_path.rb +186 -0
  42. data/lib/simplygenius/atmos/template.rb +117 -0
  43. data/lib/simplygenius/atmos/terraform_executor.rb +297 -0
  44. data/lib/simplygenius/atmos/ui.rb +173 -0
  45. data/lib/simplygenius/atmos/utils.rb +54 -0
  46. data/lib/simplygenius/atmos/version.rb +5 -0
  47. data/templates/new/config/atmos.yml +21 -13
  48. data/templates/new/config/atmos/recipes.yml +16 -0
  49. data/templates/new/config/atmos/runtime.yml +9 -0
  50. metadata +46 -40
  51. data/lib/atmos/cli.rb +0 -105
  52. data/lib/atmos/commands/account.rb +0 -65
  53. data/lib/atmos/commands/apply.rb +0 -20
  54. data/lib/atmos/commands/auth_exec.rb +0 -29
  55. data/lib/atmos/commands/base_command.rb +0 -12
  56. data/lib/atmos/commands/bootstrap.rb +0 -72
  57. data/lib/atmos/commands/container.rb +0 -58
  58. data/lib/atmos/commands/destroy.rb +0 -18
  59. data/lib/atmos/commands/generate.rb +0 -90
  60. data/lib/atmos/commands/init.rb +0 -18
  61. data/lib/atmos/commands/new.rb +0 -18
  62. data/lib/atmos/commands/otp.rb +0 -54
  63. data/lib/atmos/commands/plan.rb +0 -20
  64. data/lib/atmos/commands/secret.rb +0 -87
  65. data/lib/atmos/commands/terraform.rb +0 -52
  66. data/lib/atmos/commands/user.rb +0 -74
  67. data/lib/atmos/config.rb +0 -208
  68. data/lib/atmos/exceptions.rb +0 -9
  69. data/lib/atmos/generator.rb +0 -199
  70. data/lib/atmos/generator_factory.rb +0 -93
  71. data/lib/atmos/ipc.rb +0 -132
  72. data/lib/atmos/ipc_actions/notify.rb +0 -27
  73. data/lib/atmos/ipc_actions/ping.rb +0 -19
  74. data/lib/atmos/logging.rb +0 -160
  75. data/lib/atmos/otp.rb +0 -61
  76. data/lib/atmos/provider_factory.rb +0 -19
  77. data/lib/atmos/providers/aws/account_manager.rb +0 -82
  78. data/lib/atmos/providers/aws/auth_manager.rb +0 -208
  79. data/lib/atmos/providers/aws/container_manager.rb +0 -116
  80. data/lib/atmos/providers/aws/provider.rb +0 -51
  81. data/lib/atmos/providers/aws/s3_secret_manager.rb +0 -49
  82. data/lib/atmos/providers/aws/user_manager.rb +0 -211
  83. data/lib/atmos/settings_hash.rb +0 -90
  84. data/lib/atmos/terraform_executor.rb +0 -267
  85. data/lib/atmos/ui.rb +0 -159
  86. data/lib/atmos/utils.rb +0 -50
  87. data/lib/atmos/version.rb +0 -3
@@ -1,199 +0,0 @@
1
- require_relative '../atmos'
2
- require_relative '../atmos/ui'
3
- require 'thor'
4
- require 'find'
5
-
6
- module Atmos
7
-
8
- # From https://github.com/rubber/rubber/blob/master/lib/rubber/commands/vulcanize.rb
9
- class Generator < Thor
10
-
11
- include Thor::Actions
12
-
13
- def initialize(*args, **opts)
14
- super
15
- @dependencies = opts[:dependencies]
16
- end
17
-
18
- no_commands do
19
-
20
- include GemLogger::LoggerSupport
21
- include Atmos::UI
22
-
23
- TEMPLATES_SPEC_FILE = 'templates.yml'
24
- TEMPLATES_ACTIONS_FILE = 'templates.rb'
25
-
26
- def self.valid_templates
27
- all_entries = []
28
- source_paths_for_search.collect do |path|
29
- entries = []
30
- if Dir.exist?(path)
31
- Find.find(path) do |f|
32
- Find.prune if File.basename(f) =~ /(^\.)|svn|CVS/
33
-
34
- template_spec = File.join(f, TEMPLATES_SPEC_FILE)
35
- if File.exist?(template_spec)
36
- entries << f.sub(/^#{path}\//, '')
37
- Find.prune
38
- end
39
- end
40
- all_entries << entries.sort
41
- else
42
- logger.warn("Sourcepath does not exist: #{path}")
43
- end
44
- end
45
-
46
- return all_entries.flatten
47
- end
48
-
49
- def valid_templates
50
- self.class.valid_templates
51
- end
52
-
53
- def generate(template_names)
54
- seen = Set.new
55
- Array(template_names).each do |template_name|
56
- template_dependencies = find_dependencies(template_name)
57
- template_dependencies << template_name
58
- template_dependencies.each do |tname|
59
- apply_template(tname) unless seen.include?(tname)
60
- seen << tname
61
- end
62
- end
63
- end
64
-
65
- end
66
-
67
- protected
68
-
69
- def template_dir(name)
70
- template_dir = nil
71
- source_path = nil
72
- source_paths.each do |sp|
73
- potential_template_dir = File.join(sp, name, '')
74
- template_spec = File.join(sp, name, TEMPLATES_SPEC_FILE)
75
- if File.exist?(template_spec) && File.directory?(potential_template_dir)
76
- template_dir = potential_template_dir
77
- source_path = sp
78
- break
79
- end
80
- end
81
-
82
- unless template_dir.present?
83
- raise ArgumentError.new("Invalid template #{name}, use one of: #{valid_templates.join(', ')}")
84
- end
85
-
86
- return template_dir, source_path
87
- end
88
-
89
- def find_dependencies(name, seen=[])
90
- template_dir, source_path = template_dir(name)
91
-
92
- return [] unless @dependencies
93
-
94
- if seen.include?(name)
95
- seen << name
96
- raise ArgumentError.new("Circular template dependency: #{seen.to_a.join(" => ")}")
97
- end
98
- seen << name
99
-
100
- template_conf = load_template_config(template_dir)
101
- template_dependencies = Set.new(Array(template_conf['dependent_templates'] || []))
102
-
103
- template_dependencies.clone.each do |dep|
104
- template_dependencies.merge(find_dependencies(dep, seen.dup))
105
- end
106
-
107
- return template_dependencies.to_a
108
- end
109
-
110
- def apply_template(name)
111
- template_dir, source_path = template_dir(name)
112
- logger.debug("Applying template '#{name}' from '#{template_dir}' in sourcepath '#{source_path}'")
113
- template_conf = load_template_config(template_dir)
114
-
115
- extra_generator_steps_file = File.join(template_dir, TEMPLATES_ACTIONS_FILE)
116
-
117
- Find.find(template_dir) do |f|
118
- Find.prune if f == File.join(template_dir, TEMPLATES_SPEC_FILE) # don't copy over templates.yml
119
- Find.prune if f == extra_generator_steps_file # don't copy over templates.rb
120
-
121
- # Using File.join(x, '') to ensure trailing slash to make sure we end
122
- # up with a relative path
123
- template_rel = f.gsub(/#{File.join(template_dir, '')}/, '')
124
- source_rel = f.gsub(/#{File.join(source_path, '')}/, '')
125
- dest_rel = source_rel.gsub(/^#{File.join(name, '')}/, '')
126
-
127
- # prune non-directories at top level (the top level directory is the
128
- # template dir itself)
129
- if f !~ /\// && ! File.directory?(f)
130
- Find.prune
131
- end
132
-
133
- # Only include optional files when their conditions eval to true
134
- optional = template_conf['optional'][template_rel] rescue nil
135
- if optional
136
- exclude = ! eval(optional)
137
- logger.debug("Optional template '#{template_rel}' with condition: '#{optional}', excluding=#{exclude}")
138
- Find.prune if exclude
139
- end
140
-
141
- logger.debug("Template '#{source_rel}' => '#{dest_rel}'")
142
- if File.directory?(f)
143
- empty_directory(dest_rel)
144
- else
145
- copy_file(source_rel, dest_rel, mode: :preserve)
146
- end
147
- end
148
-
149
- if File.exist? extra_generator_steps_file
150
- eval File.read(extra_generator_steps_file), binding, extra_generator_steps_file
151
- end
152
- end
153
-
154
- def load_template_config(template_dir)
155
- YAML.load(File.read(File.join(template_dir, 'templates.yml'))) || {} rescue {}
156
- end
157
-
158
- def raw_config(yml_file)
159
- @raw_configs ||= {}
160
- @raw_configs[yml_file] ||= SettingsHash.new((YAML.load_file(yml_file) rescue {}))
161
- end
162
-
163
- def add_config(yml_file, key, value, additive: true)
164
- new_yml = SettingsHash.add_config(yml_file, key, value, additive: additive)
165
- create_file yml_file, new_yml
166
- @raw_configs.delete(yml_file) if @raw_configs
167
- end
168
-
169
- def get_config(yml_file, key)
170
- config = raw_config(yml_file)
171
- config.notation_get(key)
172
- end
173
-
174
- def config_present?(yml_file, key, value=nil)
175
- val = get_config(yml_file, key)
176
-
177
- result = val.present?
178
- if value && result
179
- if val.is_a?(Array)
180
- result = Array(value).all? {|v| val.include?(v) }
181
- else
182
- result = (val == value)
183
- end
184
- end
185
-
186
- return result
187
- end
188
-
189
- # TODO make a context object for these actions, and populate it with things
190
- # like template_dir from within apply
191
- def new_keys?(src_yml_file, dest_yml_file)
192
- src = raw_config(src_yml_file).keys.sort
193
- dest = raw_config(dest_yml_file).keys.sort
194
- (src - dest).size > 0
195
- end
196
-
197
- end
198
-
199
- end
@@ -1,93 +0,0 @@
1
- require_relative '../atmos'
2
- require_relative '../atmos/generator'
3
- require 'tmpdir'
4
- require 'fileutils'
5
- require 'git'
6
- require 'open-uri'
7
- require 'zip'
8
-
9
- module Atmos
10
- class GeneratorFactory
11
- include GemLogger::LoggerSupport
12
-
13
- def self.create(sourcepaths, **opts)
14
- expanded_sourcepaths = expand_sourcepaths(sourcepaths)
15
- klass = Class.new(Atmos::Generator) do
16
- source_paths.concat(expanded_sourcepaths)
17
- end
18
-
19
- g = klass.new([], **opts)
20
- return g
21
- end
22
-
23
- def self.expand_sourcepaths(sourcepaths)
24
- expanded_sourcepaths = []
25
- sourcepaths.each do |sourcepath|
26
-
27
- if sourcepath =~ /(\.git)|(\.zip)(#.*)?$/
28
-
29
- logger.debug("Using archive sourcepath")
30
-
31
- tmpdir = Dir.mktmpdir("atmos-templates-")
32
- at_exit { FileUtils.remove_entry(tmpdir) }
33
-
34
- template_subdir = ''
35
- if sourcepath =~ /([^#]*)#([^#]*)/
36
- sourcepath = Regexp.last_match[1]
37
- template_subdir = Regexp.last_match[2]
38
- logger.debug("Using archive subdirectory for templates: #{template_subdir}")
39
- end
40
-
41
- if sourcepath =~ /.git$/
42
-
43
- begin
44
- logger.debug("Cloning git archive to tmpdir")
45
-
46
- g = Git.clone(sourcepath, 'atmos-checkout', depth: 1, path: tmpdir)
47
- local_template_path = File.join(g.dir.path, template_subdir)
48
-
49
- expanded_sourcepaths << local_template_path
50
- logger.debug("Using git sourcepath: #{local_template_path}")
51
- rescue => e
52
- logger.log_exception(e, level: :debug)
53
- logger.warn("Could not read from git archive, ignoring sourcepath: #{sourcepath}")
54
- end
55
-
56
- elsif sourcepath =~ /.zip$/
57
-
58
- begin
59
- logger.debug("Cloning zip archive to tmpdir")
60
-
61
- open(sourcepath, 'rb') do |io|
62
- Zip::File.open_buffer(io) do |zip_file|
63
- zip_file.each do |f|
64
- fpath = File.join(tmpdir, f.name)
65
- f.extract(fpath)
66
- end
67
- end
68
- end
69
-
70
- local_template_path = File.join(tmpdir, template_subdir)
71
- expanded_sourcepaths << local_template_path
72
- logger.debug("Using zip sourcepath: #{local_template_path}")
73
- rescue => e
74
- logger.log_exception(e, level: :debug)
75
- logger.warn("Could not read from zip archive, ignoring sourcepath: #{sourcepath}")
76
- end
77
-
78
- end
79
-
80
- else
81
-
82
- logger.debug("Using local sourcepath: #{sourcepath}")
83
- expanded_sourcepaths << sourcepath
84
-
85
- end
86
-
87
- end
88
-
89
- return expanded_sourcepaths
90
- end
91
-
92
- end
93
- end
data/lib/atmos/ipc.rb DELETED
@@ -1,132 +0,0 @@
1
- require_relative '../atmos'
2
- require 'fileutils'
3
- require 'hashie'
4
-
5
- module Atmos
6
- class Ipc
7
- include GemLogger::LoggerSupport
8
-
9
- def initialize(sock_dir=Dir.tmpdir)
10
- @sock_dir = sock_dir
11
- end
12
-
13
- def listen(&block)
14
- raise "Already listening" if @server
15
-
16
- begin
17
- @socket_path = File.join(@sock_dir, 'atmos-ipc')
18
- FileUtils.rm_f(@socket_path)
19
- @server = UNIXServer.open(@socket_path)
20
- rescue ArgumentError => e
21
- if e.message =~ /too long unix socket path/ && @sock_dir != Dir.tmpdir
22
- logger.warn("Using tmp for ipc socket as path too long: #{@socket_path}")
23
- @sock_dir = Dir.tmpdir
24
- retry
25
- end
26
- end
27
-
28
- begin
29
- thread = Thread.new { run }
30
- block.call(@socket_path)
31
- ensure
32
- @server.close
33
- FileUtils.rm_f(@socket_path)
34
- @server = nil
35
- end
36
- end
37
-
38
- def generate_client_script
39
- script_file = File.join(@sock_dir, 'atmos_ipc.rb')
40
- File.write(script_file, <<~EOF
41
- #!/usr/bin/env ruby
42
- require 'socket'
43
- UNIXSocket.open('#{@socket_path}') {|c| c.puts(ARGV[0] || $stdin.read); puts c.gets }
44
- EOF
45
- )
46
- FileUtils.chmod('+x', script_file)
47
- return script_file
48
- end
49
-
50
- private
51
-
52
- def run
53
- logger.debug("Starting ipc thread")
54
- begin
55
- while @server && sock = @server.accept
56
- logger.debug("An ipc client connected")
57
- line = sock.gets
58
- logger.debug("Got ipc message: #{line.inspect}")
59
- response = {}
60
-
61
- begin
62
- msg = JSON.parse(line)
63
- msg = Hashie.symbolize_keys(msg)
64
-
65
- # enabled by default if enabled is not set (e.g. from provisioner local-exec)
66
- enabled = msg[:enabled].nil? ? true : ["true", "1"].include?(msg[:enabled].to_s)
67
-
68
- if enabled
69
- logger.debug("Dispatching IPC action")
70
- response = dispatch(msg)
71
- else
72
- response[:message] = "IPC action is not enabled"
73
- logger.debug(response[:error])
74
- end
75
- rescue => e
76
- logger.log_exception(e, "Failed to parse ipc message")
77
- response[:error] = "Failed to parse ipc message #{e.message}"
78
- end
79
-
80
- respond(sock, response)
81
- sock.close
82
- end
83
- rescue IOError, EOFError, Errno::EBADF
84
- nil
85
- rescue Exception => e
86
- logger.log_exception(e, "Ipc failure")
87
- end
88
- end
89
-
90
- def close
91
- @server.close if @server rescue nil
92
- end
93
-
94
- def load_action(name)
95
- action = nil
96
- logger.debug("Loading ipc action: #{name}")
97
- begin
98
- require "atmos/ipc_actions/#{name}"
99
- action = "Atmos::IpcActions::#{name.camelize}".constantize
100
- logger.debug("Loaded ipc action #{name}")
101
- rescue LoadError, NameError => e
102
- logger.log_exception(e, "Failed to load ipc action")
103
- end
104
- return action
105
- end
106
-
107
- def dispatch(msg)
108
- response = {}
109
- action = load_action(msg[:action])
110
- if action.nil?
111
- response[:error] = "Unsupported ipc action: #{msg.to_hash.inspect}"
112
- logger.warn(response[:error])
113
- else
114
- begin
115
- response = action.new().execute(**msg)
116
- rescue => e
117
- response[:error] = "Failure while executing ipc action: #{e.message}"
118
- logger.log_exception(e, "Failure while executing ipc action")
119
- end
120
- end
121
- return response
122
- end
123
-
124
- def respond(sock, response)
125
- msg = JSON.generate(response)
126
- logger.debug("Sending ipc response: #{msg.inspect}")
127
- sock.puts(msg)
128
- sock.flush
129
- end
130
-
131
- end
132
- end
@@ -1,27 +0,0 @@
1
- require_relative '../../atmos'
2
- require_relative '../../atmos/ui'
3
-
4
- module Atmos
5
- module IpcActions
6
- class Notify
7
- include GemLogger::LoggerSupport
8
- include Atmos::UI
9
-
10
- def initialize()
11
- end
12
-
13
- def execute(**opts)
14
-
15
- result = {
16
- 'stdout' => '',
17
- 'success' => ''
18
- }
19
-
20
- return result if Atmos.config["ipc.notify.disable"].to_s == "true"
21
- return notify(**opts)
22
-
23
- end
24
-
25
- end
26
- end
27
- end