simplygenius-atmos 0.11.8 → 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b36463da6285364bd4cedc5c58fca1dfe1a3be224e7ab5130782cfac077c6b9b
4
- data.tar.gz: 0303dd6ea2937a4f2d2c301dc817f76845fdaedb164766ed1888e8ec09fb1210
3
+ metadata.gz: 184052156c0ecd551e93ad3a1cc212bc2132f5b77409348f1c0cedcb4740b353
4
+ data.tar.gz: 67b48fb4bb4f84a922ac2879bcd38273c552fa213983f2f2d461669f6eb06587
5
5
  SHA512:
6
- metadata.gz: e8aeef7da3b8bdb24619d57c2ef13426956e064168b86182d3293bff860c6c67d3c4ac744baf6b09c126fa6e51850dbd18360fa007adfc6cbffc305c8f0acc9d
7
- data.tar.gz: c13e39a367dd9ed322106ee213816552adb1c9387f26eef72d7e96b61453cfab851fd369cda7f67eecb81d89edae07edda786980b35201982bbae3e318420c95
6
+ metadata.gz: 3f3a38df1a9759746af1999bd3e8e0fe542ddb89092a557b81720f470e7e12b3ea13eb814aa64b36f906a7534a0a96537c421bdd707cd45513e363a2c8bf8388
7
+ data.tar.gz: e68a88d3b25b8f307fec0ada80eb5f6eb9f97fdb6da550dec70db58483001b769e86873410d0328677f53ee32e9f910b0521b55a1f0ccf327668af6ad22f7546
@@ -1,3 +1,48 @@
1
+ 0.12.1 (10/14/2020)
2
+ -------------------
3
+
4
+ * fix bug with deeply nested overrides [60cb84a](https://github.com/simplygenius/atmos/commit/60cb84a)
5
+
6
+ 0.12.0 (10/12/2020)
7
+ -------------------
8
+
9
+ #### Notes on major changes
10
+
11
+ * Now testing the atmos runtime against terraform 0.13 (and 0.11, 0.12), but no changes were necessary, so it should work if you upgrade aside from recipe changes
12
+ * The fix to to make overrides (keys like ^foo to replace foo rather than add to it) work no matter where they appear in the config load chain could break compatibility if you were depending on the old behavior, i.e. you have multiple overrides for the same key with only the last one winning, or you have an override earlier in the change that was previously not taking effect
13
+
14
+ #### Full changelog
15
+
16
+ * Make overrides work no matter where they appear in the config load chain [47d73ba](https://github.com/simplygenius/atmos/commit/47d73ba)
17
+ * allow interpolation in (remote_)config_source references, e.g. for supplying an access key from ~/.atmos.yml in the url [43f0c4d](https://github.com/simplygenius/atmos/commit/43f0c4d)
18
+ * fix docker build [f4b3e2e](https://github.com/simplygenius/atmos/commit/f4b3e2e)
19
+ * fix stdin test [5bd3f95](https://github.com/simplygenius/atmos/commit/5bd3f95)
20
+ * exit with code on terraform error [2d2af2a](https://github.com/simplygenius/atmos/commit/2d2af2a)
21
+ * test against tf 0.1[123] [1bbfb3b](https://github.com/simplygenius/atmos/commit/1bbfb3b)
22
+ * add 'none' provider for tests (or if one wants to only run against terraform without aws) [991cefe](https://github.com/simplygenius/atmos/commit/991cefe)
23
+ * fix activesupport cve [3d8b30c](https://github.com/simplygenius/atmos/commit/3d8b30c)
24
+ * Add the ability to fetch atmos config from remote sources [b4b97fb](https://github.com/simplygenius/atmos/commit/b4b97fb)
25
+ * Add convenience (`atmos account setup_credentials`)for populating aws local credential stores with the aws accounts managed by atmos [05466bd](https://github.com/simplygenius/atmos/commit/05466bd)
26
+ * Add error msg for when task definition does't exist [0f8291e](https://github.com/simplygenius/atmos/commit/0f8291e)
27
+ * Fix `jsonify` to convert the correct value to JSON. (#4) [1bda229](https://github.com/simplygenius/atmos/commit/1bda229)
28
+ * Use ruby 2.4 for legacy testing since 2.3 is eol [78d2862](https://github.com/simplygenius/atmos/commit/78d2862)
29
+
30
+ 0.11.11 (02/20/2020)
31
+ --------------------
32
+
33
+ * Add the ability to setup a version requirement for forcing teams to use a consistent version of atmos [5c44ef3](https://github.com/simplygenius/atmos/commit/5c44ef3)
34
+
35
+ 0.11.10 (02/19/2020)
36
+ --------------------
37
+
38
+ * allow overriding atmos config from cli [f83902b](https://github.com/simplygenius/atmos/commit/f83902b)
39
+
40
+ 0.11.9 (02/13/2020)
41
+ -------------------
42
+
43
+ * Automatically run init when needed for current environment [f902232](https://github.com/simplygenius/atmos/commit/f902232)
44
+
45
+
1
46
  0.11.8 (02/04/2020)
2
47
  -------------------
3
48
 
@@ -2,6 +2,7 @@ require_relative '../atmos'
2
2
  require_relative '../atmos/ui'
3
3
  require 'clamp'
4
4
  require 'sigdump/setup'
5
+ require 'open-uri'
5
6
 
6
7
  Dir.glob(File.join(File.join(__dir__, 'commands'), '*.rb')) do |f|
7
8
  require_relative "commands/#{File.basename(f).sub(/\.rb$/, "")}"
@@ -51,6 +52,10 @@ module SimplyGenius
51
52
  "PATH", "adds additional paths to ruby load path",
52
53
  multivalued: true
53
54
 
55
+ option ["-o", "--override"],
56
+ "KEYVALUE", "overrides atmos configuration\nin the form 'some.config=value' where value can\nbe expressed in yaml form for complex types\ne.g. foo=1 foo=abc, foo=[x, y], foo={x: y}",
57
+ multivalued: true
58
+
54
59
  option ["-v", "--version"],
55
60
  :flag, "Shows the atmos version"
56
61
 
@@ -115,6 +120,41 @@ module SimplyGenius
115
120
  end
116
121
  end
117
122
 
123
+ def fetch_latest_version
124
+ begin
125
+ latest_ver = JSON.parse(URI.open("https://rubygems.org/api/v1/versions/simplygenius-atmos/latest.json").read)['version']
126
+ rescue => e
127
+ latest_ver = "[Version Fetch Failed]"
128
+ logger.log_exception(e, "Couldn't check latest atmos gem version", level: :debug)
129
+ end
130
+ latest_ver
131
+ end
132
+
133
+ def version_check(atmos_version)
134
+
135
+ required_ver = Atmos.config["atmos.version_requirement"]
136
+ if required_ver.present?
137
+ case required_ver
138
+
139
+ when "latest"
140
+ latest_ver = fetch_latest_version
141
+
142
+ if latest_ver != atmos_version
143
+ raise "The atmos version (#{atmos_version}) does not match the given requirement (latest: #{latest_ver})"
144
+ end
145
+
146
+ when /[~<>=]*\s*[\d\.]*/
147
+ if ! Gem::Dependency.new('', required_ver).match?('', atmos_version)
148
+ raise "The atmos version (#{atmos_version}) does not match the given requirement (#{required_ver})"
149
+ end
150
+
151
+ else
152
+ raise "Invalid atmos.version_requirement, should be 'latest' or in a gem dependency form"
153
+ end
154
+ end
155
+
156
+ end
157
+
118
158
  # hook into clamp lifecycle to force logging setup even when we are calling
119
159
  # a subcommand
120
160
  def parse(arguments)
@@ -128,6 +168,13 @@ module SimplyGenius
128
168
 
129
169
  Logging.setup_logging(level, color?, log)
130
170
 
171
+ override_list.each do |o|
172
+ k, v = o.split("=")
173
+ v = YAML.load(v)
174
+ logger.debug("Overriding config '#{k}' = #{v.inspect}")
175
+ Atmos.config.[]=(k, v, additive: false)
176
+ end
177
+
131
178
  UI.color_enabled = color?
132
179
 
133
180
  Atmos.config.add_user_load_path(*load_path_list)
@@ -138,6 +185,8 @@ module SimplyGenius
138
185
  logger.info "Atmos Version #{VERSION}"
139
186
  exit(0)
140
187
  end
188
+
189
+ version_check(VERSION)
141
190
  end
142
191
  end
143
192
 
@@ -62,6 +62,42 @@ module SimplyGenius
62
62
  end
63
63
  end
64
64
 
65
+ subcommand "setup_credentials", "Convenience that adds accounts to the local aws\ncredentials store" do
66
+
67
+ option ["-u", "--user"],
68
+ "USERNAME", "The username in the cloud provider\n", required: true
69
+
70
+ option ["-k", "--key"],
71
+ "KEY", "The access key in the cloud provider\n"
72
+
73
+ option ["-s", "--secret"],
74
+ "SECRET", "The access secret in the cloud provider\n"
75
+
76
+ option ["-d", "--default"],
77
+ :flag, "Sets as default credentials\n"
78
+
79
+ option ["-f", "--force"],
80
+ :flag, "Forces overwrites of existing\n"
81
+
82
+ option ["-n", "--nowrite"],
83
+ :flag, "Trial run without writing results to files\n"
84
+
85
+ def execute
86
+
87
+ if ! key.present?
88
+ key = ask("Input your access key: ") { |q| q.echo = "*" }
89
+ raise ArgumentError.new("An access key is required") if key.blank?
90
+ end
91
+ if ! secret.present?
92
+ secret = ask("Input your access secret: ") { |q| q.echo = "*" }
93
+ raise ArgumentError.new("An access secret is required") if secret.blank?
94
+ end
95
+
96
+ Atmos.config.provider.account_manager.setup_credentials(username: user, access_key: key, access_secret: secret,
97
+ become_default: default?, force: force?, nowrite: nowrite?)
98
+ end
99
+ end
100
+
65
101
  end
66
102
 
67
103
  end
@@ -14,6 +14,9 @@ module SimplyGenius
14
14
  args = ["apply"]
15
15
  args << "--get-modules" unless Atmos.config["atmos.terraform.disable_auto_modules"].to_s == "true"
16
16
  @terraform_arguments.insert(0, *args)
17
+
18
+ self.auto_init = true
19
+
17
20
  super
18
21
  end
19
22
 
@@ -68,6 +68,7 @@ module SimplyGenius
68
68
  rescue TerraformExecutor::ProcessFailed => e
69
69
  logger.error(e.message)
70
70
  logger.error(rebootstrap_msg)
71
+ exit(1)
71
72
  end
72
73
  end
73
74
  end
@@ -7,7 +7,6 @@ module SimplyGenius
7
7
  module Commands
8
8
 
9
9
  class Init < Terraform
10
- include FileUtils
11
10
 
12
11
  def self.description
13
12
  "Runs terraform init"
@@ -17,17 +16,7 @@ module SimplyGenius
17
16
  @terraform_arguments.insert(0, "init")
18
17
  super
19
18
 
20
- if ! Atmos.config["atmos.terraform.disable_shared_plugins"]
21
- home_dir = OS.windows? ? File.join("~", "Application Data") : "~"
22
- shared_plugins_dir = File.expand_path(File.join(home_dir,".terraform.d", "plugins"))
23
- logger.debug("Updating shared terraform plugins dir: #{shared_plugins_dir}")
24
- mkdir_p(shared_plugins_dir)
25
- terraform_plugins_dir = File.join(Atmos.config.tf_working_dir,'recipes', '.terraform', 'plugins')
26
- if File.exist?(terraform_plugins_dir)
27
- cp_r("#{terraform_plugins_dir}/.", shared_plugins_dir)
28
- end
29
- end
30
-
19
+ init_shared_plugins
31
20
  end
32
21
 
33
22
  end
@@ -14,6 +14,9 @@ module SimplyGenius
14
14
  args = ["plan"]
15
15
  args << "--get-modules" unless Atmos.config["atmos.terraform.disable_auto_modules"].to_s == "true"
16
16
  @terraform_arguments.insert(0, *args)
17
+
18
+ self.auto_init = true
19
+
17
20
  super
18
21
  end
19
22
 
@@ -6,6 +6,9 @@ module SimplyGenius
6
6
  module Commands
7
7
 
8
8
  class Terraform < BaseCommand
9
+ include FileUtils
10
+
11
+ attr_accessor :auto_init
9
12
 
10
13
  def self.description
11
14
  "Runs terraform"
@@ -17,6 +20,31 @@ module SimplyGenius
17
20
  @terraform_arguments = arguments
18
21
  end
19
22
 
23
+ def init_automatically(auth_env, get_modules)
24
+ tf_init_dir = File.join(Atmos.config.tf_working_dir, '.terraform')
25
+ backend_initialized = File.exist?(File.join(tf_init_dir, 'terraform.tfstate'))
26
+ auto_init_enabled = Atmos.config["atmos.terraform.auto_init"].to_s == "true"
27
+
28
+ if auto_init && auto_init_enabled && ! backend_initialized
29
+ exe = TerraformExecutor.new(process_env: auth_env)
30
+ exe.run("init", get_modules: get_modules.present?)
31
+ init_shared_plugins
32
+ end
33
+ end
34
+
35
+ def init_shared_plugins
36
+ if ! Atmos.config["atmos.terraform.disable_shared_plugins"]
37
+ home_dir = OS.windows? ? File.join("~", "Application Data") : "~"
38
+ shared_plugins_dir = File.expand_path(File.join(home_dir,".terraform.d", "plugins"))
39
+ logger.debug("Updating shared terraform plugins dir: #{shared_plugins_dir}")
40
+ mkdir_p(shared_plugins_dir)
41
+ terraform_plugins_dir = File.join(Atmos.config.tf_working_dir,'recipes', '.terraform', 'plugins')
42
+ if File.exist?(terraform_plugins_dir)
43
+ cp_r("#{terraform_plugins_dir}/.", shared_plugins_dir)
44
+ end
45
+ end
46
+ end
47
+
20
48
  def execute
21
49
 
22
50
  unless Atmos.config.is_atmos_repo?
@@ -28,11 +56,15 @@ module SimplyGenius
28
56
 
29
57
  Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
30
58
  begin
31
- exe = TerraformExecutor.new(process_env: auth_env)
32
59
  get_modules = @terraform_arguments.delete("--get-modules")
60
+
61
+ init_automatically(auth_env, get_modules)
62
+
63
+ exe = TerraformExecutor.new(process_env: auth_env)
33
64
  exe.run(*@terraform_arguments, get_modules: get_modules.present?)
34
65
  rescue TerraformExecutor::ProcessFailed => e
35
66
  logger.error(e.message)
67
+ exit(1)
36
68
  end
37
69
  end
38
70
  end
@@ -61,7 +61,7 @@ module SimplyGenius
61
61
  result[k] = ev
62
62
  end
63
63
  else
64
- result["data"] = JSON.generate(result)
64
+ result["data"] = JSON.generate(obj)
65
65
  end
66
66
 
67
67
  return result
@@ -5,6 +5,7 @@ require_relative '../atmos/plugin_manager'
5
5
  require 'yaml'
6
6
  require 'fileutils'
7
7
  require 'find'
8
+ require 'open-uri'
8
9
 
9
10
  module SimplyGenius
10
11
  module Atmos
@@ -26,7 +27,7 @@ module SimplyGenius
26
27
  @config_file = config ? File.expand_path(config, root_dir) : File.join(root_dir, "config", "atmos.yml")
27
28
  @user_config_file = "~/.atmos.yml"
28
29
  @tmp_root = File.join(root_dir, "tmp")
29
- @included_configs = []
30
+ @included_configs = {}
30
31
  end
31
32
 
32
33
  def is_atmos_repo?
@@ -39,9 +40,9 @@ module SimplyGenius
39
40
  return result
40
41
  end
41
42
 
42
- def []=(key, value)
43
+ def []=(key, value, additive: true)
43
44
  load
44
- result = @config.notation_put(key, value)
45
+ result = @config.notation_put(key, value, additive: additive)
45
46
  return result
46
47
  end
47
48
 
@@ -114,6 +115,7 @@ module SimplyGenius
114
115
  if merge_to_existing
115
116
  existing = load_file(user_config_file, SettingsHash.new)
116
117
  data = config_merge(existing, data, ["saving #{user_config_file}"])
118
+ data = finalize_merge(data)
117
119
  end
118
120
  File.write(user_config_file, YAML.dump(data.to_hash))
119
121
  File.chmod(0600, user_config_file)
@@ -132,21 +134,27 @@ module SimplyGenius
132
134
  when Hash
133
135
  result = lhs.deep_dup
134
136
 
135
- lhs.each do |k, v|
136
- if k =~ /^\^(.*)/
137
- key = k.is_a?(Symbol) ? $1.to_sym : $1
138
- result[key] = result.delete(k)
139
- end
140
- end
141
-
142
137
  rhs.each do |k, v|
143
- if k =~ /^\^(.*)/
144
- key = k.is_a?(Symbol) ? $1.to_sym : $1
145
- result[key] = v
146
- else
147
- result[k] = config_merge(result[k], v, debug_state + [k])
138
+ new_state = debug_state + [k]
139
+
140
+ # The load sequence could have multiple overrides and its not
141
+ # obvious to the user which are lhs vs rhs, so rather than having
142
+ # one seem to win arbitrarily, we collect them all additively
143
+ # under their key, then at the end of the load process we push the
144
+ # override back as a replacement for its base key in the
145
+ # finalize_merge method. This means that if one has multiple
146
+ # overrides for the same key (not usually what one wants), those
147
+ # overrides get merged together additively before replacing the
148
+ # base. Thus the need for the log messages below.
149
+ #
150
+ if k =~ /^\^/
151
+ logger.debug { "Override seen at #{new_state.join(" -> ")}" }
152
+ logger.warn { "Multiple overrides on a single key seen at #{new_state.join(" -> ")}" } if result.has_key?(k)
148
153
  end
154
+
155
+ result[k] = config_merge(result[k], v, new_state)
149
156
  end
157
+
150
158
  when Enumerable
151
159
  result = lhs + rhs
152
160
  else
@@ -168,6 +176,37 @@ module SimplyGenius
168
176
 
169
177
  private
170
178
 
179
+ def finalize_merge(config)
180
+ result = config.deep_dup
181
+
182
+ config.each do |k, v|
183
+
184
+ key = k
185
+
186
+ if k =~ /^\^(.*)/
187
+ key = k.is_a?(Symbol) ? $1.to_sym : $1
188
+ result[key] = result.delete(k)
189
+ end
190
+
191
+ if v.is_a?(Hash)
192
+ result[key] = finalize_merge(v)
193
+ end
194
+
195
+ end
196
+
197
+ return result
198
+ end
199
+
200
+ def load_remote_config_sources(config, *remote_sources)
201
+ remote_sources.each do |remote_source|
202
+ logger.debug("Loading remote atmos config file: #{remote_source}")
203
+ contents = URI.open(remote_source).read
204
+ config = load_config(remote_source, contents, config)
205
+ end
206
+
207
+ config
208
+ end
209
+
171
210
  def load_config_sources(relative_root, config, *patterns)
172
211
  patterns.each do |pattern|
173
212
  logger.debug("Loading atmos config files using pattern: #{pattern}")
@@ -217,26 +256,26 @@ module SimplyGenius
217
256
  @full_config = load_file(config_file, SettingsHash.new)
218
257
  end
219
258
 
220
- @full_config = load_config_sources(File.dirname(config_file), @full_config, *Array(@full_config.notation_get("atmos.config_sources")))
259
+ @user_config_file = @full_config.notation_get("atmos.user_config") || @user_config_file
260
+ @user_config_file = File.expand_path(@user_config_file)
261
+ user_config_file_data = load_file(@user_config_file)
262
+ temp_settings = create_settings(config_merge(@full_config, user_config_file_data, [@user_config_file]), finalize: true)
263
+
264
+ @full_config = load_config_sources(File.dirname(config_file), @full_config, *Array(temp_settings.notation_get("atmos.config_sources")))
265
+ @full_config = load_remote_config_sources(@full_config, *Array(temp_settings.notation_get("atmos.remote_config_sources")))
221
266
 
222
267
  @full_config['provider'] = provider_name = @full_config['provider'] || 'aws'
223
268
 
224
269
  @full_config = load_submap(File.dirname(config_file), 'providers', provider_name, @full_config)
225
270
  @full_config = load_submap(File.dirname(config_file), 'environments', atmos_env, @full_config)
226
271
 
227
- @user_config_file = @full_config.notation_get("atmos.user_config") || @user_config_file
228
- @user_config_file = File.expand_path(@user_config_file)
229
- @full_config = load_file(user_config_file, @full_config)
272
+ @full_config = config_merge(@full_config, user_config_file_data, [@user_config_file])
230
273
 
231
- global = SettingsHash.new(@full_config.reject {|k, v| ['providers', 'environments'].include?(k) })
232
- conf = config_merge(global, {
233
- atmos_env: atmos_env,
234
- atmos_working_group: working_group,
235
- atmos_version: VERSION
236
- }, ["builtins"])
274
+ conf = create_settings(@full_config, finalize: true)
275
+
276
+ # hash emptied out to allow GC of all loaded file contents
277
+ @included_configs = {}
237
278
 
238
- conf.error_resolver = ->(statement) { find_config_error(statement) }
239
- conf.enable_expansion = true
240
279
  conf
241
280
 
242
281
  end
@@ -245,15 +284,8 @@ module SimplyGenius
245
284
  def load_file(file, config=SettingsHash.new, &block)
246
285
  if File.exist?(file)
247
286
  logger.debug("Loading atmos config file #{file}")
248
- data = YAML.load_file(file)
249
- if ! data.is_a?(Hash)
250
- logger.debug("Skipping invalid atmos config file (not hash-like): #{file}")
251
- else
252
- data = SettingsHash.new(data)
253
- data = block.call(data) if block
254
- config = config_merge(config, data, [file])
255
- @included_configs << file
256
- end
287
+ contents = File.read(file)
288
+ config = load_config(file, contents, config, &block)
257
289
  else
258
290
  logger.debug "Could not find an atmos config file at: #{file}"
259
291
  end
@@ -261,16 +293,49 @@ module SimplyGenius
261
293
  config
262
294
  end
263
295
 
296
+ def load_config(location, yml_string, config=SettingsHash.new, &block)
297
+ data = YAML.load(yml_string)
298
+
299
+ if ! data.is_a?(Hash)
300
+ logger.debug("Skipping invalid atmos config (not hash-like): #{location}")
301
+ else
302
+ data = SettingsHash.new(data)
303
+ data = block.call(data) if block
304
+ # if lhs has a override ^, then it loses it when rhs gets merged in, which breaks things for subsequent merges
305
+ config = config_merge(config, data, [location])
306
+ @included_configs[location] = yml_string
307
+ end
308
+
309
+ config
310
+ end
311
+
312
+ def create_settings(config, finalize: true)
313
+ builtins = {
314
+ atmos_env: atmos_env,
315
+ atmos_working_group: working_group,
316
+ atmos_version: VERSION
317
+ }
318
+
319
+ global = SettingsHash.new(config.reject {|k, v| ['providers', 'environments'].include?(k) })
320
+ conf = config_merge(global, builtins, ["builtins"])
321
+ conf = finalize_merge(conf) if finalize
322
+
323
+ conf.error_resolver = ->(statement) { find_config_error(statement) }
324
+ conf.enable_expansion = true
325
+
326
+ conf
327
+ end
328
+
264
329
  def find_config_error(statement)
265
330
  filename = nil
266
331
  line = 0
267
332
 
268
- @included_configs.each do |c|
333
+ @included_configs.each do |location, contents|
269
334
  current_line = 0
270
- File.foreach(c) do |f|
335
+ contents.each_line do |line|
271
336
  current_line += 1
272
- if f.include?(statement)
273
- filename = c
337
+ if line.include?(statement)
338
+ filename = location
274
339
  line = current_line
275
340
  break
276
341
  end
@@ -7,14 +7,15 @@ module SimplyGenius
7
7
  include GemLogger::LoggerSupport
8
8
 
9
9
  def self.get(name)
10
- @provider ||= begin
10
+ @providers ||= {}
11
+ provider = @providers[name] ||= begin
11
12
  logger.debug("Loading provider: #{name}")
12
13
  require "simplygenius/atmos/providers/#{name}/provider"
13
- provider = "SimplyGenius::Atmos::Providers::#{name.camelize}::Provider".constantize
14
- logger.debug("Loaded provider #{provider}")
15
- provider.new(name)
14
+ provider_class = "SimplyGenius::Atmos::Providers::#{name.camelize}::Provider".constantize
15
+ logger.debug("Loaded provider #{provider_class}")
16
+ provider_class.new(name)
16
17
  end
17
- return @provider
18
+ return provider
18
19
  end
19
20
 
20
21
  end
@@ -1,5 +1,6 @@
1
1
  require_relative '../../../atmos'
2
2
  require 'aws-sdk-organizations'
3
+ require 'inifile'
3
4
 
4
5
  module SimplyGenius
5
6
  module Atmos
@@ -75,6 +76,76 @@ module SimplyGenius
75
76
  return result
76
77
  end
77
78
 
79
+ def setup_credentials(username:, access_key:, access_secret:, become_default: false, force: false, nowrite: false)
80
+ creds = File.expand_path("~/.aws/credentials")
81
+ config = File.expand_path("~/.aws/config")
82
+
83
+ creds_data = IniFile.load(creds) || IniFile.new
84
+ config_data = IniFile.load(config) || IniFile.new
85
+
86
+ org = Atmos.config["org"]
87
+ accounts = Atmos.config.account_hash
88
+
89
+ # Our entrypoint account (the ops env/account) is the account we
90
+ # have credentials for, and typically one authenticate using the
91
+ # credentials for that account, then assume role (<env>-admin) to
92
+ # actually operate in each env, even for the ops account
93
+ ops_config = Atmos::Config.new("ops")
94
+ entrypoint_section = become_default ? "default" : org
95
+ entrypoint_config_section = become_default ? "default" : "profile #{org}"
96
+ write_entrypoint = true
97
+ if config_data.has_section?(entrypoint_config_section) || creds_data.has_section?(entrypoint_section)
98
+ if force
99
+ logger.info "Overwriting pre-existing sections: '#{entrypoint_config_section}'/'#{entrypoint_section}'"
100
+ else
101
+ logger.info "Skipping pre-existing sections (use force to overwrite): '#{entrypoint_config_section}'/'#{entrypoint_section}'"
102
+ write_entrypoint = false
103
+ end
104
+ end
105
+ if write_entrypoint
106
+ config_data[entrypoint_config_section]["region"] = ops_config["region"]
107
+ creds_data[entrypoint_section]["aws_access_key_id"] = access_key
108
+ creds_data[entrypoint_section]["aws_secret_access_key"] = access_secret
109
+ creds_data[entrypoint_section]["mfa_serial"] = "arn:aws:iam::#{accounts["ops"]}:mfa/#{username}"
110
+ end
111
+
112
+ accounts.each do |env, account_id|
113
+ env_config = Atmos::Config.new(env)
114
+
115
+ section = "#{org}-#{env}"
116
+ config_section = "profile #{section}"
117
+
118
+ if config_data.has_section?(config_section) || creds_data.has_section?(section)
119
+ if force
120
+ logger.info "Overwriting pre-existing sections: '#{config_section}'/'#{section}'"
121
+ else
122
+ logger.info "Skipping pre-existing sections (use force to overwrite): '#{config_section}'/'#{section}'"
123
+ next
124
+ end
125
+ end
126
+
127
+ config_data[config_section]["source_profile"] = entrypoint_section
128
+ role_name = env_config["auth.assume_role_name"]
129
+ config_data[config_section]["role_arn"] = "arn:aws:iam::#{account_id}:role/#{role_name}"
130
+ end
131
+
132
+ if nowrite
133
+ logger.info "Trial run only, would write the following:\n"
134
+ puts "*** #{config}:\n\n"
135
+ puts config_data.to_s
136
+
137
+ puts "\n\n*** #{creds}:\n\n"
138
+ puts creds_data.to_s
139
+ else
140
+ logger.info "Writing credentials to disk"
141
+ mkdir_p(File.dirname(config))
142
+ mv config, "#{config}.bak" if File.exist?(config)
143
+ mv creds, "#{creds}.bak" if File.exist?(creds)
144
+ config_data.write(filename: config)
145
+ creds_data.write(filename: creds)
146
+ end
147
+
148
+ end
78
149
  end
79
150
 
80
151
  end
@@ -198,6 +198,8 @@ module SimplyGenius
198
198
  logger.info "Running task as '#{task_opts[:launch_type]}'"
199
199
  end
200
200
 
201
+ raise "Could not find a task definition in AWS for '#{name}'" if defn_arn.blank?
202
+
201
203
  resp = ecs.describe_task_definition(task_definition: defn_arn)
202
204
  defn = resp.task_definition
203
205
  raise "Invalid Launch type '#{launch_type}'" unless (defn.requires_compatibilities + defn.compatibilities).include?(launch_type)
@@ -0,0 +1,24 @@
1
+ require_relative '../../../atmos'
2
+
3
+ module SimplyGenius
4
+ module Atmos
5
+ module Providers
6
+ module None
7
+
8
+ class AuthManager
9
+ include GemLogger::LoggerSupport
10
+
11
+ def initialize(provider)
12
+ @provider = provider
13
+ end
14
+
15
+ def authenticate(system_env, **opts, &block)
16
+ logger.debug("Calling none authentication target")
17
+ block.call(system_env)
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,47 @@
1
+ require_relative '../../../atmos'
2
+
3
+ Dir.glob(File.join(__dir__, '*.rb')) do |f|
4
+ require_relative "#{File.basename(f).sub(/\.rb$/, "")}"
5
+ end
6
+
7
+ module SimplyGenius
8
+ module Atmos
9
+ module Providers
10
+ module None
11
+
12
+ class Provider
13
+ include GemLogger::LoggerSupport
14
+
15
+ def initialize(name)
16
+ @name = name
17
+ end
18
+
19
+ def auth_manager
20
+ @auth_manager ||= begin
21
+ AuthManager.new(self)
22
+ end
23
+ end
24
+
25
+ def user_manager
26
+ raise NotImplementedError.new("No user manager in none provider")
27
+ end
28
+
29
+ def account_manager
30
+ raise NotImplementedError.new("No account manager in none provider")
31
+ end
32
+
33
+ def secret_manager
34
+ @secret_manager ||= begin
35
+ SecretManager.new(self)
36
+ end
37
+ end
38
+
39
+ def container_manager
40
+ raise NotImplementedError.new("No container manager in none provider")
41
+ end
42
+ end
43
+
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ require_relative '../../../atmos'
2
+
3
+ module SimplyGenius
4
+ module Atmos
5
+ module Providers
6
+ module None
7
+
8
+ class SecretManager
9
+ include GemLogger::LoggerSupport
10
+
11
+ def initialize(provider)
12
+ @provider = provider
13
+ @secrets = {}
14
+ end
15
+
16
+ def set(key, value, force: false)
17
+ if @secrets.has_key?(key) && ! force
18
+ raise "A value already exists for the given key, force overwrite or delete first"
19
+ end
20
+ @secrets[key] = value
21
+ end
22
+
23
+ def get(key)
24
+ @secrets[key]
25
+ end
26
+
27
+ def delete(key)
28
+ @secrets.delete(key)
29
+ end
30
+
31
+ def to_h
32
+ @secrets.to_h
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -113,7 +113,7 @@ module SimplyGenius
113
113
  begin
114
114
  logger.debug("Cloning zip archive to tmpdir")
115
115
 
116
- open(sourcepath, 'rb') do |io|
116
+ URI.open(sourcepath, 'rb') do |io|
117
117
  Zip::File.open_buffer(io) do |zip_file|
118
118
  zip_file.each do |f|
119
119
  fpath = File.join(tmpdir, f.name)
@@ -1,5 +1,5 @@
1
1
  module SimplyGenius
2
2
  module Atmos
3
- VERSION = "0.11.8"
3
+ VERSION = "0.12.1"
4
4
  end
5
5
  end
@@ -67,4 +67,9 @@ atmos:
67
67
  # to the directory containing atmos.yml
68
68
  #
69
69
  config_sources:
70
- - atmos/*.y{,a}ml
70
+ - atmos/*.y{,a}ml
71
+ # A list of remote atmos configuration yml files.
72
+ # Takes any URI supported by ruby's open-uri
73
+ #
74
+ remote_config_sources:
75
+ # - https://some.url/to/config.yml
@@ -35,6 +35,12 @@ atmos:
35
35
  # gets expanded at runtime
36
36
  load_path:
37
37
 
38
+ # Forces one to use the version of atmos that is given. This version
39
+ # specifier can be 'latest' or in the form of a gem version dependency
40
+ # specifier, e.g. '~> 0.11.10'. If unset, then no version check will be
41
+ # performed
42
+ version_requirement:
43
+
38
44
  # Configure the mechanism that allows terraform to callback into atmos
39
45
  ipc:
40
46
  # Disables all IPC callbacks into atmos from terraform
@@ -125,3 +131,5 @@ atmos:
125
131
  working_dir_links: ['modules', 'templates', 'bin', '.terraform-version']
126
132
  # Set true if running terraform version < 0.11.x
127
133
  compat11: false
134
+ # Automatically run "init" if needed when using "atmos plan|apply"
135
+ auto_init: true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplygenius-atmos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.8
4
+ version: 0.12.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Conway
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-02-04 00:00:00.000000000 Z
11
+ date: 2020-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -28,142 +28,156 @@ dependencies:
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: 12.3.3
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: 12.3.3
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '3.7'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '3.7'
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: concurrent-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: simplecov
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - "~>"
73
+ - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: '0.10'
75
+ version: '0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - "~>"
80
+ - - ">="
67
81
  - !ruby/object:Gem::Version
68
- version: '0.10'
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: coveralls
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - "~>"
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: '0.8'
89
+ version: 0.8.23
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - "~>"
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
- version: '0.8'
96
+ version: 0.8.23
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: test_construct
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - "~>"
101
+ - - ">="
88
102
  - !ruby/object:Gem::Version
89
- version: 2.0.1
103
+ version: '0'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - "~>"
108
+ - - ">="
95
109
  - !ruby/object:Gem::Version
96
- version: 2.0.1
110
+ version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: vcr
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - "~>"
115
+ - - ">="
102
116
  - !ruby/object:Gem::Version
103
- version: 4.0.0
117
+ version: '0'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - "~>"
122
+ - - ">="
109
123
  - !ruby/object:Gem::Version
110
- version: 4.0.0
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: webmock
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - "~>"
129
+ - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: 3.3.0
131
+ version: '0'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - "~>"
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: 3.3.0
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: pry
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
- - - "~>"
143
+ - - ">="
130
144
  - !ruby/object:Gem::Version
131
- version: 0.11.3
145
+ version: '0'
132
146
  type: :development
133
147
  prerelease: false
134
148
  version_requirements: !ruby/object:Gem::Requirement
135
149
  requirements:
136
- - - "~>"
150
+ - - ">="
137
151
  - !ruby/object:Gem::Version
138
- version: 0.11.3
152
+ version: '0'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: pry-byebug
141
155
  requirement: !ruby/object:Gem::Requirement
142
156
  requirements:
143
- - - "~>"
157
+ - - ">="
144
158
  - !ruby/object:Gem::Version
145
- version: 3.6.0
159
+ version: '0'
146
160
  type: :development
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
- - - "~>"
164
+ - - ">="
151
165
  - !ruby/object:Gem::Version
152
- version: 3.6.0
166
+ version: '0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: activesupport
155
169
  requirement: !ruby/object:Gem::Requirement
156
170
  requirements:
157
- - - "~>"
171
+ - - ">="
158
172
  - !ruby/object:Gem::Version
159
- version: 5.2.1
173
+ version: 5.2.4.3
160
174
  type: :runtime
161
175
  prerelease: false
162
176
  version_requirements: !ruby/object:Gem::Requirement
163
177
  requirements:
164
- - - "~>"
178
+ - - ">="
165
179
  - !ruby/object:Gem::Version
166
- version: 5.2.1
180
+ version: 5.2.4.3
167
181
  - !ruby/object:Gem::Dependency
168
182
  name: gem_logger
169
183
  requirement: !ruby/object:Gem::Requirement
@@ -472,6 +486,20 @@ dependencies:
472
486
  - - "~>"
473
487
  - !ruby/object:Gem::Version
474
488
  version: 1.1.2
489
+ - !ruby/object:Gem::Dependency
490
+ name: inifile
491
+ requirement: !ruby/object:Gem::Requirement
492
+ requirements:
493
+ - - "~>"
494
+ - !ruby/object:Gem::Version
495
+ version: 3.0.0
496
+ type: :runtime
497
+ prerelease: false
498
+ version_requirements: !ruby/object:Gem::Requirement
499
+ requirements:
500
+ - - "~>"
501
+ - !ruby/object:Gem::Version
502
+ version: 3.0.0
475
503
  - !ruby/object:Gem::Dependency
476
504
  name: deepsort
477
505
  requirement: !ruby/object:Gem::Requirement
@@ -558,6 +586,9 @@ files:
558
586
  - lib/simplygenius/atmos/providers/aws/s3_secret_manager.rb
559
587
  - lib/simplygenius/atmos/providers/aws/ssm_secret_manager.rb
560
588
  - lib/simplygenius/atmos/providers/aws/user_manager.rb
589
+ - lib/simplygenius/atmos/providers/none/auth_manager.rb
590
+ - lib/simplygenius/atmos/providers/none/provider.rb
591
+ - lib/simplygenius/atmos/providers/none/secret_manager.rb
561
592
  - lib/simplygenius/atmos/settings_hash.rb
562
593
  - lib/simplygenius/atmos/source_path.rb
563
594
  - lib/simplygenius/atmos/template.rb
@@ -574,7 +605,7 @@ homepage: https://github.com/simplygenius/atmos
574
605
  licenses:
575
606
  - Apache-2.0
576
607
  metadata: {}
577
- post_install_message:
608
+ post_install_message:
578
609
  rdoc_options: []
579
610
  require_paths:
580
611
  - lib
@@ -589,8 +620,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
589
620
  - !ruby/object:Gem::Version
590
621
  version: '0'
591
622
  requirements: []
592
- rubygems_version: 3.0.3
593
- signing_key:
623
+ rubygems_version: 3.1.4
624
+ signing_key:
594
625
  specification_version: 4
595
626
  summary: Atmos provides a terraform scaffold for creating cloud system architectures
596
627
  test_files: []