simplygenius-atmos 0.12.0 → 0.13.2

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: a43cd732a3f97e0fc2884f1b284b8f389db9b1845879a1e8cd5b23a657b9dab6
4
- data.tar.gz: 0b84e5d5026b849bac355875bc4759b8cfc21abc4ad51627d2e35626f928f2e4
3
+ metadata.gz: b3da6d623f0f47dd62493eaf985c527b153698844d26027c2838660f4fdfe93f
4
+ data.tar.gz: 8f7deb9ff4397607aad846869898c9fd28df2c484b588175e9fb19bb614860d4
5
5
  SHA512:
6
- metadata.gz: 84bfe472a2bef731c2cd3dc715ca2b0d214a343cef6491f09bc4762445d7faf340b704366a5b0e099c3e9a42cb6f4e23fecf918671cdeb6a51b4a1a7e15a993e
7
- data.tar.gz: 2a3f7167cd23068e9e8ea810810ed3e896b36d6c803b8f844b38bfa11e8127dd37505fcf91995321d9a53af4d851236eebebfc8d6421a6c03109aa8e90267596
6
+ metadata.gz: da42675bc9bb7d9b5923fb1f9a98b043cd16acb1fe70332e290d6398d7138db7c9c7d0b02c4c85200634c7de5379810655394eae283e0c04e5a4a3515018519e
7
+ data.tar.gz: b946205f7c8893d4e8e54af2cd0a1309d407f830287a27cf597daeefc2b38e032bb9e3ea1e75ff38f738f635b8b8ebd6c91f90a749b97707fd1cd20081c05127
data/CHANGELOG.md CHANGED
@@ -1,3 +1,43 @@
1
+ 0.13.2 (01/04/2022)
2
+ -------------------
3
+
4
+ * require top level active_support to fix issue with 7.0.0 [2b2f584](../../commit/2b2f584)
5
+
6
+ 0.13.1 (05/04/2021)
7
+ -------------------
8
+
9
+ * fix console exception, extend console startup wait loop, and add better console logging and error reporting [2d44553](../../commit/2d44553)
10
+ * fix logging [3cc07b9](../../commit/3cc07b9)
11
+ * allow selection of specific items with cli config dump [675ebfe](../../commit/675ebfe)
12
+ * cli help line formatting [13b36a3](../../commit/13b36a3)
13
+ * add container pull helper [22518f3](../../commit/22518f3)
14
+
15
+ 0.13.0 (01/20/2021)
16
+ -------------------
17
+
18
+ #### Notes on major changes
19
+
20
+ * Now testing the atmos runtime against terraform 0.14 (and 0.11, 0.13)
21
+ * The ability to link files into the terraform execution directory was enhanced, but still doesn't work for the .terraform.lock.hcl as it is overwritten by terraform and doesn't follow the link
22
+
23
+ #### Full changelog
24
+
25
+ * exclude some new taskdef attributes for creation of new taskdef during deploy [a01b997](https://github.com/simplygenius/atmos/commit/a01b997)
26
+ * add debug logging for aws sdk logger [55dd303](https://github.com/simplygenius/atmos/commit/55dd303)
27
+ * directory sorting made more consistent across platforms [13622ff](https://github.com/simplygenius/atmos/commit/13622ff)
28
+ * switch ci/cd from travis to github actions [13622ff](https://github.com/simplygenius/atmos/commit/13622ff)
29
+ * fix test for tf 0.14 [122f861](https://github.com/simplygenius/atmos/commit/122f861)
30
+ * replace plugin sharing with built in terraform variant [eb75266](https://github.com/simplygenius/atmos/commit/eb75266)
31
+ * allow more options for linking in non-tf files into working dir [9878336](https://github.com/simplygenius/atmos/commit/9878336)
32
+ * sort secret list [6b2dbfe](https://github.com/simplygenius/atmos/commit/6b2dbfe)
33
+ * Only run terraform init when needed [d77186b](https://github.com/simplygenius/atmos/commit/d77186b)
34
+
35
+
36
+ 0.12.1 (10/14/2020)
37
+ -------------------
38
+
39
+ * fix bug with deeply nested overrides [60cb84a](https://github.com/simplygenius/atmos/commit/60cb84a)
40
+
1
41
  0.12.0 (10/12/2020)
2
42
  -------------------
3
43
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/simplygenius/atmos.svg?branch=master)](https://travis-ci.org/simplygenius/atmos)
1
+ [![Build Status](https://github.com/simplygenius/atmos/workflows/CD/badge.svg)](https://github.com/simplygenius/atmos/actions)
2
2
  [![Coverage Status](https://coveralls.io/repos/github/simplygenius/atmos/badge.svg?branch=master)](https://coveralls.io/github/simplygenius/atmos?branch=master)
3
3
  [![Gitter](https://badges.gitter.im/simplygenius/atmos.svg)](https://gitter.im/simplygenius/atmos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
4
4
 
@@ -30,22 +30,22 @@ module SimplyGenius
30
30
  end
31
31
 
32
32
  option ["-d", "--debug"],
33
- :flag, "debug output\n",
33
+ :flag, "debug output",
34
34
  default: false
35
35
 
36
36
  option ["-q", "--quiet"],
37
- :flag, "suppress output\n",
37
+ :flag, "suppress output",
38
38
  default: false
39
39
 
40
40
  option ["-c", "--[no-]color"],
41
- :flag, "colorize output (or not)\n (default: $stdout.tty?)"
41
+ :flag, "colorize output (or not) (default: $stdout.tty?)"
42
42
 
43
43
  option ["-e", "--atmos-env"],
44
- 'ENV', "The atmos environment\n",
44
+ 'ENV', "The atmos environment",
45
45
  environment_variable: 'ATMOS_ENV', default: 'ops'
46
46
 
47
47
  option ["-g", "--atmos-group"],
48
- 'GROUP', "The atmos working group\n for selecting recipe groups\n",
48
+ 'GROUP', "The atmos working group for selecting recipe groups",
49
49
  default: 'default'
50
50
 
51
51
  option ["-p", "--load-path"],
@@ -53,7 +53,7 @@ module SimplyGenius
53
53
  multivalued: true
54
54
 
55
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}",
56
+ "KEYVALUE", "overrides atmos configuration in the form 'some.config=value' where value can be expressed in yaml form for complex types e.g. foo=1 foo=abc, foo=[x, y], foo={x: y}",
57
57
  multivalued: true
58
58
 
59
59
  option ["-v", "--version"],
@@ -64,7 +64,7 @@ module SimplyGenius
64
64
  end
65
65
 
66
66
  option ["-l", "--[no-]log"],
67
- :flag, "log to file in addition to terminal (or not)\n",
67
+ :flag, "log to file in addition to terminal (or not)",
68
68
  default: true
69
69
 
70
70
 
@@ -110,11 +110,29 @@ module SimplyGenius
110
110
  option ["-j", "--json"],
111
111
  :flag, "Dump config as json instead of yaml"
112
112
 
113
+ parameter "PATH",
114
+ "The dot notation path of a specific config item to get",
115
+ required: false
116
+
113
117
  def execute
118
+ if path
119
+ result = Atmos.config[path]
120
+ result = case result
121
+ when Hash
122
+ result.to_h
123
+ when Array
124
+ result.to_a
125
+ else
126
+ result
127
+ end
128
+ else
129
+ result = Atmos.config.to_h
130
+ end
131
+
114
132
  if json?
115
- output = JSON.pretty_generate(Atmos.config.to_h)
133
+ output = JSON.pretty_generate(result)
116
134
  else
117
- output = YAML.dump(Atmos.config.to_h)
135
+ output = YAML.dump(result).sub(/^\s*---\s*/, '')
118
136
  end
119
137
  logger.info output
120
138
  end
@@ -213,3 +231,37 @@ module SimplyGenius
213
231
 
214
232
  end
215
233
  end
234
+
235
+ # Hack to make clamp usage less of a pain to get long lines to fit within a
236
+ # standard terminal width
237
+ class Clamp::Help::Builder
238
+
239
+ def word_wrap(text, line_width:)
240
+ text.split("\n").collect do |line|
241
+ line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip.split("\n") : line
242
+ end.flatten
243
+ end
244
+
245
+ def string
246
+ line_width = 79
247
+ indent_size = 4
248
+ indent = " " * indent_size
249
+ StringIO.new.tap do |out|
250
+ lines.each do |line|
251
+ case line
252
+ when Array
253
+ out << indent
254
+ out.puts(line[0])
255
+ formatted_line = line[1].gsub(/\((default|required)/, "\n\\0")
256
+ word_wrap(formatted_line, line_width: (line_width - indent_size * 2)).each do |l|
257
+ out << (indent * 2)
258
+ out.puts(l)
259
+ end
260
+ else
261
+ out.puts(line)
262
+ end
263
+ end
264
+ end.string
265
+ end
266
+
267
+ end
@@ -15,13 +15,13 @@ module SimplyGenius
15
15
  subcommand "create", "Create a new account" do
16
16
 
17
17
  option ["-s", "--source-env"],
18
- "SOURCE_ENV", "Base the new env on a clone of the given one\n"
18
+ "SOURCE_ENV", "Base the new env on a clone of the given one"
19
19
 
20
20
  option ["-e", "--email"],
21
- "EMAIL", "override default email used for new account\n"
21
+ "EMAIL", "override default email used for new account"
22
22
 
23
23
  option ["-n", "--name"],
24
- "NAME", "override default name used for new account\n"
24
+ "NAME", "override default name used for new account"
25
25
 
26
26
  parameter "ENV",
27
27
  "The name of the new env to create"
@@ -62,25 +62,25 @@ 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
65
+ subcommand "setup_credentials", "Convenience that adds accounts to the local aws credentials store" do
66
66
 
67
67
  option ["-u", "--user"],
68
- "USERNAME", "The username in the cloud provider\n", required: true
68
+ "USERNAME", "The username in the cloud provider", required: true
69
69
 
70
70
  option ["-k", "--key"],
71
- "KEY", "The access key in the cloud provider\n"
71
+ "KEY", "The access key in the cloud provider"
72
72
 
73
73
  option ["-s", "--secret"],
74
- "SECRET", "The access secret in the cloud provider\n"
74
+ "SECRET", "The access secret in the cloud provider"
75
75
 
76
76
  option ["-d", "--default"],
77
- :flag, "Sets as default credentials\n"
77
+ :flag, "Sets as default credentials"
78
78
 
79
79
  option ["-f", "--force"],
80
- :flag, "Forces overwrites of existing\n"
80
+ :flag, "Forces overwrites of existing"
81
81
 
82
82
  option ["-n", "--nowrite"],
83
- :flag, "Trial run without writing results to files\n"
83
+ :flag, "Trial run without writing results to files"
84
84
 
85
85
  def execute
86
86
 
@@ -12,7 +12,7 @@ module SimplyGenius
12
12
  end
13
13
 
14
14
  option ["-r", "--role"],
15
- 'ROLE', "overrides assume role name\n"
15
+ 'ROLE', "overrides assume role name"
16
16
 
17
17
  parameter "COMMAND ...", "command to exec", :attribute_name => :command
18
18
 
@@ -11,7 +11,7 @@ module SimplyGenius
11
11
  end
12
12
 
13
13
  option ["-f", "--force"],
14
- :flag, "forces bootstrap\n"
14
+ :flag, "forces bootstrap"
15
15
 
16
16
  def execute
17
17
  orig_config = Atmos.config
@@ -15,22 +15,44 @@ module SimplyGenius
15
15
  end
16
16
 
17
17
  option ["-c", "--cluster"],
18
- "CLUSTER", "The cluster name\n",
18
+ "CLUSTER", "The cluster name",
19
19
  required: true
20
20
 
21
21
  option ["-r", "--role"],
22
- "ROLE", "The role to assume when deploying\n"
22
+ "ROLE", "The role to assume when deploying"
23
+
24
+ subcommand "pull", "Pulls a container image from repository" do
25
+
26
+ option ["-v", "--revision"],
27
+ "REVISION", "Use as the remote image revision"
28
+
29
+ parameter "NAME",
30
+ "The name of the service (or task) to pull the image for"
31
+
32
+ def execute
33
+ Atmos.config.provider.auth_manager.authenticate(ENV, role: role) do |auth_env|
34
+ ClimateControl.modify(auth_env) do
35
+ mgr = Atmos.config.provider.container_manager
36
+
37
+ result = mgr.pull(name, revision: revision)
38
+
39
+ logger.info "Container pulled:\n #{display result}"
40
+ end
41
+ end
42
+ end
43
+
44
+ end
23
45
 
24
46
  subcommand "push", "Only push a container image without activating it" do
25
47
 
26
48
  option ["-i", "--image"],
27
- "IMAGE", "The local container image to deploy\nDefaults to service/task name"
49
+ "IMAGE", "The local container image to deploy Defaults to service/task name"
28
50
 
29
51
  option ["-v", "--revision"],
30
- "REVISION", "Use as the remote image revision\n"
52
+ "REVISION", "Use as the remote image revision"
31
53
 
32
54
  parameter "NAME ...",
33
- "The name of the service (or task) to deploy\nWhen multiple, the first is the primary, and\nthe rest get deployed with its image"
55
+ "The name of the service (or task) to deploy. When multiple, the first is the primary, and the rest get deployed with its image"
34
56
 
35
57
  def default_image
36
58
  name_list.first
@@ -55,22 +77,22 @@ module SimplyGenius
55
77
  subcommand "activate", "Activate a container that has already been pushed" do
56
78
 
57
79
  option ["-v", "--revision"],
58
- "REVISION", "Use the given revision of the pushed image\nto activate\n"
80
+ "REVISION", "Use the given revision of the pushed image to activate"
59
81
 
60
82
  option ["-w", "--wait"],
61
- :flag, "Wait for service to become stable after deploy\nnon-zero exit on fail"
83
+ :flag, "Wait for service to become stable after deploy non-zero exit on fail"
62
84
 
63
85
  option ["-l", "--list"],
64
- :flag, "List the most recent pushed images\n"
86
+ :flag, "List the most recent pushed images"
65
87
 
66
88
  option ["-t", "--tagcount"],
67
- "N", "Only show the last N items when listing\n",
89
+ "N", "Only show the last N items when listing",
68
90
  default: 10 do |s|
69
91
  Integer(s)
70
92
  end
71
93
 
72
94
  parameter "NAME ...",
73
- "The name of the service (or task) to activate\nWhen multiple, the first is the primary, and\nthe rest get activated with its image"
95
+ "The name of the service (or task) to activate. When multiple, the first is the primary, and the rest get activated with its image"
74
96
 
75
97
  def execute
76
98
  Atmos.config.provider.auth_manager.authenticate(ENV, role: role) do |auth_env|
@@ -125,16 +147,16 @@ module SimplyGenius
125
147
  subcommand "deploy", "Push and activate a container" do
126
148
 
127
149
  option ["-i", "--image"],
128
- "IMAGE", "The local container image to deploy\nDefaults to service/task name"
150
+ "IMAGE", "The local container image to deploy. Defaults to service/task name"
129
151
 
130
152
  option ["-w", "--wait"],
131
- :flag, "Wait for service to become stable after deploy\nnon-zero exit on fail"
153
+ :flag, "Wait for service to become stable after deploy non-zero exit on fail"
132
154
 
133
155
  option ["-v", "--revision"],
134
- "REVISION", "Use as the remote image revision\n"
156
+ "REVISION", "Use as the remote image revision"
135
157
 
136
158
  parameter "NAME ...",
137
- "The name of the service (or task) to deploy\nWhen multiple, the first is the primary, and\nthe rest get deployed with its image"
159
+ "The name of the service (or task) to deploy. When multiple, the first is the primary, and the rest get deployed with its image"
138
160
 
139
161
  def default_image
140
162
  name_list.first
@@ -171,10 +193,10 @@ module SimplyGenius
171
193
  subcommand "console", "Spawn a console and attach to it" do
172
194
 
173
195
  option ["-p", "--persist"],
174
- :flag, "Leave the task running after disconnect\n"
196
+ :flag, "Leave the task running after disconnect"
175
197
 
176
198
  parameter "NAME",
177
- "The name of the service (or task) to attach\nthe console to"
199
+ "The name of the service (or task) to attach the console to"
178
200
 
179
201
  def execute
180
202
  Atmos.config.provider.auth_manager.authenticate(ENV, role: role) do |auth_env|
@@ -191,8 +213,12 @@ module SimplyGenius
191
213
  logger.debug "Run task result: #{result}"
192
214
  begin
193
215
  match = result[:log_match]
194
- local_command = local_command.collect {|c| match.names.each {|n| c = c.gsub("<#{n}>", match[n]) }; c }
195
- system(*local_command)
216
+ if match.blank?
217
+ logger.error("Aborting, the console task failed to produce the expected output: #{log_pattern}")
218
+ else
219
+ local_command = local_command.collect {|c| match.names.each {|n| c = c.gsub("<#{n}>", match[n]) }; c }
220
+ system(*local_command)
221
+ end
196
222
  ensure
197
223
  if persist?
198
224
  logger.info "Console disconnected, you can reconnect with: #{local_command.join(" ")}"
@@ -34,12 +34,12 @@ module SimplyGenius
34
34
  option ["-l", "--list"],
35
35
  :flag, "list available templates"
36
36
  option ["-u", "--update"],
37
- :flag, "update all installed templates\n"
37
+ :flag, "update all installed templates"
38
38
  option ["-p", "--sourcepath"],
39
39
  "PATH", "search for templates using given sourcepath",
40
40
  multivalued: true
41
41
  option ["-r", "--[no-]sourcepaths"],
42
- :flag, "clear sourcepaths from template search\n", default: true
42
+ :flag, "clear sourcepaths from template search", default: true
43
43
  option ["-c", "--context"],
44
44
  "CONTEXT", "provide context variables (dot notation)",
45
45
  multivalued: true
@@ -15,8 +15,6 @@ module SimplyGenius
15
15
  def execute
16
16
  @terraform_arguments.insert(0, "init")
17
17
  super
18
-
19
- init_shared_plugins
20
18
  end
21
19
 
22
20
  end
@@ -13,7 +13,7 @@ module SimplyGenius
13
13
  end
14
14
 
15
15
  option ["-s", "--secret"],
16
- 'SECRET', "The otp secret\nWill save for future use"
16
+ 'SECRET', "The otp secret. Will save for future use"
17
17
 
18
18
  option ["-c", "--clipboard"],
19
19
  :flag,
@@ -31,7 +31,7 @@ module SimplyGenius
31
31
  subcommand "set", "Sets the secret value" do
32
32
 
33
33
  option ["-f", "--force"],
34
- :flag, "forces updates for pre-existing secret\n",
34
+ :flag, "forces updates for pre-existing secret",
35
35
  default: false
36
36
 
37
37
  parameter "KEY",
@@ -60,7 +60,7 @@ module SimplyGenius
60
60
  Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
61
61
  ClimateControl.modify(auth_env) do
62
62
  logger.info "Secret keys are:"
63
- Atmos.config.provider.secret_manager.to_h.keys.each {|k| logger.info k}
63
+ Atmos.config.provider.secret_manager.to_h.keys.sort.each {|k| logger.info k}
64
64
  end
65
65
  end
66
66
 
@@ -21,27 +21,23 @@ module SimplyGenius
21
21
  end
22
22
 
23
23
  def init_automatically(auth_env, get_modules)
24
- tf_init_dir = File.join(Atmos.config.tf_working_dir, '.terraform')
24
+ tf_init_dir = File.join(Atmos.config.tf_working_dir, 'recipes', '.terraform')
25
25
  backend_initialized = File.exist?(File.join(tf_init_dir, 'terraform.tfstate'))
26
26
  auto_init_enabled = Atmos.config["atmos.terraform.auto_init"].to_s == "true"
27
27
 
28
28
  if auto_init && auto_init_enabled && ! backend_initialized
29
29
  exe = TerraformExecutor.new(process_env: auth_env)
30
30
  exe.run("init", get_modules: get_modules.present?)
31
- init_shared_plugins
32
31
  end
33
32
  end
34
33
 
35
- def init_shared_plugins
34
+ def enable_shared_plugins(env)
36
35
  if ! Atmos.config["atmos.terraform.disable_shared_plugins"]
37
36
  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
37
+ plugin_cache_dir = File.expand_path(File.join(home_dir,".terraform.d", "plugin-cache"))
38
+ logger.debug("Plugin cache dir: #{plugin_cache_dir}")
39
+ mkdir_p(plugin_cache_dir)
40
+ env["TF_PLUGIN_CACHE_DIR"] = plugin_cache_dir
45
41
  end
46
42
  end
47
43
 
@@ -58,6 +54,8 @@ module SimplyGenius
58
54
  begin
59
55
  get_modules = @terraform_arguments.delete("--get-modules")
60
56
 
57
+ enable_shared_plugins(auth_env)
58
+
61
59
  init_automatically(auth_env, get_modules)
62
60
 
63
61
  exe = TerraformExecutor.new(process_env: auth_env)
@@ -13,21 +13,21 @@ module SimplyGenius
13
13
  "Useful utilities when calling out from terraform with data.external"
14
14
  end
15
15
 
16
- subcommand "jsonify", "Manages json on stdin/out to conform\nto use in terraform data.external" do
16
+ subcommand "jsonify", "Manages json on stdin/out to conform to use in terraform data.external" do
17
17
 
18
18
  banner "Ensures json output only contains a single level Hash with string values (e.g. when execing curl returns a deep json hash of mixed values)"
19
19
 
20
20
  option ["-a", "--atmos_config"],
21
- :flag, "Includes the atmos config in the\nhash from parsing json on stdin"
21
+ :flag, "Includes the atmos config in the hash from parsing json on stdin"
22
22
 
23
23
  option ["-c", "--clipboard"],
24
- :flag, "Copies the actual command used\nto the clipboard to allow external debugging"
24
+ :flag, "Copies the actual command used to the clipboard to allow external debugging"
25
25
 
26
26
  option ["-j", "--json"],
27
27
  :flag, "The command output is parsed as json"
28
28
 
29
29
  option ["-x", "--[no-]exit"],
30
- :flag, "Exit with the command's exit code\non failure (or not)", default: true
30
+ :flag, "Exit with the command's exit code on failure (or not)", default: true
31
31
 
32
32
  parameter "COMMAND ...",
33
33
  "The command to call", :attribute_name => :command
@@ -73,9 +73,9 @@ module SimplyGenius
73
73
  chunk = $stdin.read_nonblock(1)
74
74
  data = chunk + $stdin.read
75
75
  logger.debug("Received stdin: " + data)
76
- rescue Errno::EAGAIN
76
+ rescue EOFError, SystemCallError => e # All Errno exceptions
77
77
  data = nil
78
- logger.debug("No stdin")
78
+ logger.debug("No stdin due to: #{e}")
79
79
  end
80
80
  return data
81
81
  end
@@ -14,31 +14,31 @@ module SimplyGenius
14
14
  subcommand "create", "Create a new user" do
15
15
 
16
16
  option ["-f", "--force"],
17
- :flag, "forces deletion/updates for pre-existing\nresources",
17
+ :flag, "forces deletion/updates for pre-existing resources",
18
18
  default: false
19
19
 
20
20
  option ["-l", "--login"],
21
- :flag, "generate a login password\n",
21
+ :flag, "generate a login password",
22
22
  default: false
23
23
 
24
24
  option ["-m", "--mfa"],
25
- :flag, "setup a mfa device\n",
25
+ :flag, "setup a mfa device",
26
26
  default: false
27
27
 
28
28
  option ["-k", "--key"],
29
- :flag, "create access keys\n",
29
+ :flag, "create access keys",
30
30
  default: false
31
31
 
32
32
  option ["-p", "--public-key"],
33
- "PUBLIC_KEY", "add ssh public key\n"
33
+ "PUBLIC_KEY", "add ssh public key"
34
34
 
35
35
  option ["-g", "--group"],
36
36
  "GROUP",
37
- "associate the given groups to new user\n",
37
+ "associate the given groups to new user",
38
38
  multivalued: true
39
39
 
40
40
  parameter "USERNAME",
41
- "The username of the user to add\nShould be an email address" do |u|
41
+ "The username of the user to add. Should be an email address" do |u|
42
42
  raise ArgumentError.new("Not an email") if u !~ URI::MailTo::EMAIL_REGEXP
43
43
  u
44
44
  end
@@ -114,13 +114,14 @@ module SimplyGenius
114
114
 
115
115
  if merge_to_existing
116
116
  existing = load_file(user_config_file, SettingsHash.new)
117
- data = config_merge(existing, data, ["saving #{user_config_file}"], finalize: true)
117
+ data = config_merge(existing, data, ["saving #{user_config_file}"])
118
+ data = finalize_merge(data)
118
119
  end
119
120
  File.write(user_config_file, YAML.dump(data.to_hash))
120
121
  File.chmod(0600, user_config_file)
121
122
  end
122
123
 
123
- def config_merge(lhs, rhs, debug_state=[], finalize: true)
124
+ def config_merge(lhs, rhs, debug_state=[])
124
125
  result = nil
125
126
 
126
127
  return rhs if lhs.nil?
@@ -136,30 +137,22 @@ module SimplyGenius
136
137
  rhs.each do |k, v|
137
138
  new_state = debug_state + [k]
138
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
+ #
139
150
  if k =~ /^\^/
140
151
  logger.debug { "Override seen at #{new_state.join(" -> ")}" }
141
152
  logger.warn { "Multiple overrides on a single key seen at #{new_state.join(" -> ")}" } if result.has_key?(k)
142
153
  end
143
154
 
144
- result[k] = config_merge(result[k], v, new_state, finalize: finalize)
145
- end
146
-
147
- # The load sequence could have multiple overrides and its not
148
- # obvious to the user which are lhs vs rhs, so rather than having
149
- # one seem to win arbitrarily, we collect them all additively under
150
- # their key, then at the end of the load process we push the
151
- # override back as a replacement for its base key.
152
- # This means that if one has multiple overrides for the same key
153
- # (not usually what one wants), those overrides get merged together
154
- # additively before replacing the base. Thus the need for the debug
155
- # log message above.
156
- if finalize
157
- result.each do |k, v|
158
- if k =~ /^\^(.*)/
159
- key = k.is_a?(Symbol) ? $1.to_sym : $1
160
- result[key] = result.delete(k)
161
- end
162
- end
155
+ result[k] = config_merge(result[k], v, new_state)
163
156
  end
164
157
 
165
158
  when Enumerable
@@ -183,6 +176,27 @@ module SimplyGenius
183
176
 
184
177
  private
185
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
+
186
200
  def load_remote_config_sources(config, *remote_sources)
187
201
  remote_sources.each do |remote_source|
188
202
  logger.debug("Loading remote atmos config file: #{remote_source}")
@@ -205,7 +219,7 @@ module SimplyGenius
205
219
  pattern = File.expand_path(pattern)
206
220
  logger.debug("Expanded pattern: #{pattern}")
207
221
 
208
- Dir[pattern].each do |f|
222
+ Dir[pattern].sort.each do |f|
209
223
  config = load_file(f, config)
210
224
  end
211
225
  end
@@ -222,7 +236,7 @@ module SimplyGenius
222
236
 
223
237
  begin
224
238
  submap = config.deep_fetch(group, name)
225
- config = config_merge(config, submap, ["#{submap_file} submap(#{group}.#{name})"], finalize: false)
239
+ config = config_merge(config, submap, ["#{submap_file} submap(#{group}.#{name})"])
226
240
  rescue
227
241
  logger.debug("No #{group} config found for '#{name}'")
228
242
  end
@@ -245,7 +259,7 @@ module SimplyGenius
245
259
  @user_config_file = @full_config.notation_get("atmos.user_config") || @user_config_file
246
260
  @user_config_file = File.expand_path(@user_config_file)
247
261
  user_config_file_data = load_file(@user_config_file)
248
- temp_settings = create_settings(config_merge(@full_config, user_config_file_data, [@user_config_file], finalize: false), finalize: false)
262
+ temp_settings = create_settings(config_merge(@full_config, user_config_file_data, [@user_config_file]), finalize: true)
249
263
 
250
264
  @full_config = load_config_sources(File.dirname(config_file), @full_config, *Array(temp_settings.notation_get("atmos.config_sources")))
251
265
  @full_config = load_remote_config_sources(@full_config, *Array(temp_settings.notation_get("atmos.remote_config_sources")))
@@ -255,7 +269,7 @@ module SimplyGenius
255
269
  @full_config = load_submap(File.dirname(config_file), 'providers', provider_name, @full_config)
256
270
  @full_config = load_submap(File.dirname(config_file), 'environments', atmos_env, @full_config)
257
271
 
258
- @full_config = config_merge(@full_config, user_config_file_data, [@user_config_file], finalize: false)
272
+ @full_config = config_merge(@full_config, user_config_file_data, [@user_config_file])
259
273
 
260
274
  conf = create_settings(@full_config, finalize: true)
261
275
 
@@ -288,7 +302,7 @@ module SimplyGenius
288
302
  data = SettingsHash.new(data)
289
303
  data = block.call(data) if block
290
304
  # if lhs has a override ^, then it loses it when rhs gets merged in, which breaks things for subsequent merges
291
- config = config_merge(config, data, [location], finalize: false)
305
+ config = config_merge(config, data, [location])
292
306
  @included_configs[location] = yml_string
293
307
  end
294
308
 
@@ -303,7 +317,8 @@ module SimplyGenius
303
317
  }
304
318
 
305
319
  global = SettingsHash.new(config.reject {|k, v| ['providers', 'environments'].include?(k) })
306
- conf = config_merge(global, builtins, ["builtins"], finalize: finalize)
320
+ conf = config_merge(global, builtins, ["builtins"])
321
+ conf = finalize_merge(conf) if finalize
307
322
 
308
323
  conf.error_resolver = ->(statement) { find_config_error(statement) }
309
324
  conf.enable_expansion = true
@@ -16,6 +16,33 @@ module SimplyGenius
16
16
  @provider = provider
17
17
  end
18
18
 
19
+ def pull(ecr_repo, revision: nil)
20
+
21
+ revision ||= 'latest'
22
+ result = {}
23
+
24
+ ecr = ::Aws::ECR::Client.new
25
+ resp = nil
26
+
27
+ resp = ecr.get_authorization_token
28
+ auth_data = resp.authorization_data.first
29
+ token = auth_data.authorization_token
30
+ endpoint = auth_data.proxy_endpoint
31
+ user, password = Base64.decode64(token).split(':')
32
+
33
+ # docker login into the ECR repo for the current account so that we can pull/push to it
34
+ run("docker", "login", "-u", user, "-p", password, endpoint)#, stdin_data: token)
35
+
36
+ image="#{ecr_repo}:#{revision}"
37
+ ecs_image="#{endpoint.sub(/https?:\/\//, '')}/#{image}"
38
+
39
+ logger.info "Pulling image from ECR repo #{ecs_image}"
40
+ run("docker", "pull", "#{ecs_image}")
41
+
42
+ result[:remote_image] = "#{ecs_image}"
43
+ return result
44
+ end
45
+
19
46
  def push(ecs_name, local_image,
20
47
  ecr_repo: ecs_name, revision: nil)
21
48
 
@@ -64,7 +91,8 @@ module SimplyGenius
64
91
 
65
92
  new_defn = latest_defn.to_h
66
93
  [:revision, :status, :task_definition_arn,
67
- :requires_attributes, :compatibilities].each do |attr|
94
+ :requires_attributes, :compatibilities,
95
+ :registered_at, :registered_by, :deregistered_at].each do |attr|
68
96
  new_defn.delete(attr)
69
97
  end
70
98
  new_defn[:container_definitions].each {|c| c[:image] = remote_image}
@@ -228,9 +256,12 @@ module SimplyGenius
228
256
 
229
257
  waiter_regexp = Regexp.new(waiter_log_pattern)
230
258
  log_stream = "#{log_stream_prefix}/#{name}/#{task_id}"
231
- logger.info "Task started, looking for log pattern in group=#{log_group} stream=#{log_stream}"
259
+ logger.info "Task started, waiting for remote command"
260
+ logger.debug "Looking for log_pattern='#{waiter_log_pattern}' in group=#{log_group} stream=#{log_stream}"
232
261
  log_token = nil
233
- 10.times do
262
+ count = (Atmos.config['atmos.container.console.retry_count'] || 30).to_i
263
+ interval = (Atmos.config['atmos.container.console.retry_interval'] || 2).to_i
264
+ count.times do
234
265
  resp = cwl.get_log_events(log_group_name: log_group, log_stream_name: log_stream, start_from_head: true, next_token: log_token)
235
266
  resp.events.each do |e|
236
267
  logger.debug("Task log #{e.timestamp}: #{e.message}")
@@ -239,8 +270,8 @@ module SimplyGenius
239
270
  return result # return, not break due to doubly nested iterator
240
271
  end
241
272
  end
242
- log_token = resp.next_forward_token
243
- sleep 1
273
+ log_token = resp.next_forward_token if resp.events.length > 0
274
+ sleep interval
244
275
  end
245
276
  end
246
277
 
@@ -1,5 +1,7 @@
1
1
  require_relative '../../../atmos'
2
2
 
3
+ require 'aws-sdk-core'
4
+
3
5
  Dir.glob(File.join(__dir__, '*.rb')) do |f|
4
6
  require_relative "#{File.basename(f).sub(/\.rb$/, "")}"
5
7
  end
@@ -11,6 +13,7 @@ module SimplyGenius
11
13
 
12
14
  class Provider
13
15
  include GemLogger::LoggerSupport
16
+ ::Aws.config.update(logger: logger, log_level: :debug) if logger.debug?
14
17
 
15
18
  def initialize(name)
16
19
  @name = name
@@ -308,7 +308,7 @@ module SimplyGenius
308
308
 
309
309
  def clean_links
310
310
  Find.find(Atmos.config.tf_working_dir) do |f|
311
- Find.prune if f =~ /\/.terraform\/modules\//
311
+ Find.prune if f =~ /\/.terraform\//
312
312
  File.delete(f) if File.symlink?(f)
313
313
  end
314
314
  end
@@ -318,13 +318,30 @@ module SimplyGenius
318
318
  working_dir_links ||= ['modules', 'templates']
319
319
  working_dir_links.each do |subdir|
320
320
  source = File.join(Atmos.config.root_dir, subdir)
321
- ln_sf(source, Atmos.config.tf_working_dir) if File.exist?(source)
321
+ parts = File.split(subdir)
322
+ target_dir = Atmos.config.tf_working_dir
323
+ if parts[0] != "."
324
+ target_dir = File.join(Atmos.config.tf_working_dir, parts[0])
325
+ mkdir_p(target_dir)
326
+ end
327
+ ln_sf(source, target_dir) if File.exist?(source)
322
328
  end
323
329
  end
324
330
 
325
331
  def link_recipes
326
332
  @recipes.each do |recipe|
327
- ln_sf(File.join(Atmos.config.root_dir, 'recipes', "#{recipe}.tf"), tf_recipes_dir)
333
+ recipe_satisfied = false
334
+ ["#{recipe}.tf", recipe].each do |recipe_variant|
335
+ fqrecipe = File.join(Atmos.config.root_dir, 'recipes', recipe_variant)
336
+ if File.exist?(fqrecipe)
337
+ ln_sf(fqrecipe, tf_recipes_dir)
338
+ recipe_satisfied = true
339
+ break
340
+ else
341
+ logger.debug("Recipe target does not exist: #{fqrecipe}")
342
+ end
343
+ end
344
+ logger.error("Recipe '#{recipe}' is not present") unless recipe_satisfied
328
345
  end
329
346
  end
330
347
 
@@ -1,5 +1,5 @@
1
1
  module SimplyGenius
2
2
  module Atmos
3
- VERSION = "0.12.0"
3
+ VERSION = "0.13.2"
4
4
  end
5
5
  end
@@ -5,6 +5,7 @@ require_relative 'atmos/version'
5
5
  # ui.rb when running its spec:
6
6
  # NameError: uninitialized constant ActiveSupport::JSON Did you mean? JSON
7
7
  #
8
+ require 'active_support'
8
9
  require 'active_support/json'
9
10
  require 'active_support/core_ext/object/json'
10
11
 
@@ -18,4 +19,7 @@ module SimplyGenius
18
19
  end
19
20
 
20
21
  require_relative 'atmos/logging'
22
+ # Need to setup logging before loading any other files
23
+ SimplyGenius::Atmos::Logging.setup_logging(:info, false, nil)
24
+
21
25
  require_relative 'atmos/config'
@@ -119,12 +119,12 @@ atmos:
119
119
  terraform:
120
120
  # Disable module fetch from convenience plan/apply commands
121
121
  disable_auto_modules: false
122
- # By default (value=false), `atmos init` will update the terraform user
123
- # plugin directory (~/.terraform.d/plugins) with the plugins for the current
124
- # env/group so that they can be reused across all env/group combinations.
125
- # Otherwise, disabling this functionality (value=true) means that each
126
- # env/group combination will be independent and download all plugins for
127
- # itself only
122
+ # By default (value=false), `atmos init` (and auto init) will set
123
+ # TF_PLUGIN_CACHE_DIR to ~/.terraform.d/plugin-cache so that when terraform
124
+ # installs providers/plugins they can be reused across all env/group
125
+ # combinations. Otherwise, disabling this functionality (value=true) means
126
+ # that each env/group combination will be independent and download all
127
+ # plugins for itself only
128
128
  disable_shared_plugins: false
129
129
  # Customize what gets linked into the working directory that terraform gets
130
130
  # executed in
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.12.0
4
+ version: 0.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Conway
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2022-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -620,7 +620,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
620
620
  - !ruby/object:Gem::Version
621
621
  version: '0'
622
622
  requirements: []
623
- rubygems_version: 3.1.4
623
+ rubygems_version: 3.2.32
624
624
  signing_key:
625
625
  specification_version: 4
626
626
  summary: Atmos provides a terraform scaffold for creating cloud system architectures