simplygenius-atmos 0.7.1 → 0.8.0

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