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 +4 -4
- data/CHANGELOG.md +40 -0
- data/README.md +1 -1
- data/lib/simplygenius/atmos/cli.rb +61 -9
- data/lib/simplygenius/atmos/commands/account.rb +10 -10
- data/lib/simplygenius/atmos/commands/auth_exec.rb +1 -1
- data/lib/simplygenius/atmos/commands/bootstrap.rb +1 -1
- data/lib/simplygenius/atmos/commands/container.rb +44 -18
- data/lib/simplygenius/atmos/commands/generate.rb +2 -2
- data/lib/simplygenius/atmos/commands/init.rb +0 -2
- data/lib/simplygenius/atmos/commands/otp.rb +1 -1
- data/lib/simplygenius/atmos/commands/secret.rb +2 -2
- data/lib/simplygenius/atmos/commands/terraform.rb +8 -10
- data/lib/simplygenius/atmos/commands/tfutil.rb +6 -6
- data/lib/simplygenius/atmos/commands/user.rb +7 -7
- data/lib/simplygenius/atmos/config.rb +42 -27
- data/lib/simplygenius/atmos/providers/aws/container_manager.rb +36 -5
- data/lib/simplygenius/atmos/providers/aws/provider.rb +3 -0
- data/lib/simplygenius/atmos/terraform_executor.rb +20 -3
- data/lib/simplygenius/atmos/version.rb +1 -1
- data/lib/simplygenius/atmos.rb +4 -0
- data/templates/new/config/atmos/runtime.yml +6 -6
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3da6d623f0f47dd62493eaf985c527b153698844d26027c2838660f4fdfe93f
|
4
|
+
data.tar.gz: 8f7deb9ff4397607aad846869898c9fd28df2c484b588175e9fb19bb614860d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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://
|
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
|
33
|
+
:flag, "debug output",
|
34
34
|
default: false
|
35
35
|
|
36
36
|
option ["-q", "--quiet"],
|
37
|
-
:flag, "suppress output
|
37
|
+
:flag, "suppress output",
|
38
38
|
default: false
|
39
39
|
|
40
40
|
option ["-c", "--[no-]color"],
|
41
|
-
:flag, "colorize output (or not)
|
41
|
+
:flag, "colorize output (or not) (default: $stdout.tty?)"
|
42
42
|
|
43
43
|
option ["-e", "--atmos-env"],
|
44
|
-
'ENV', "The atmos environment
|
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
|
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
|
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)
|
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(
|
133
|
+
output = JSON.pretty_generate(result)
|
116
134
|
else
|
117
|
-
output = YAML.dump(
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
74
|
+
"SECRET", "The access secret in the cloud provider"
|
75
75
|
|
76
76
|
option ["-d", "--default"],
|
77
|
-
:flag, "Sets as default credentials
|
77
|
+
:flag, "Sets as default credentials"
|
78
78
|
|
79
79
|
option ["-f", "--force"],
|
80
|
-
:flag, "Forces overwrites of existing
|
80
|
+
:flag, "Forces overwrites of existing"
|
81
81
|
|
82
82
|
option ["-n", "--nowrite"],
|
83
|
-
:flag, "Trial run without writing results to files
|
83
|
+
:flag, "Trial run without writing results to files"
|
84
84
|
|
85
85
|
def execute
|
86
86
|
|
@@ -15,22 +15,44 @@ module SimplyGenius
|
|
15
15
|
end
|
16
16
|
|
17
17
|
option ["-c", "--cluster"],
|
18
|
-
"CLUSTER", "The cluster name
|
18
|
+
"CLUSTER", "The cluster name",
|
19
19
|
required: true
|
20
20
|
|
21
21
|
option ["-r", "--role"],
|
22
|
-
"ROLE", "The role to assume when deploying
|
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
|
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
|
52
|
+
"REVISION", "Use as the remote image revision"
|
31
53
|
|
32
54
|
parameter "NAME ...",
|
33
|
-
"The name of the service (or task) to deploy
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
156
|
+
"REVISION", "Use as the remote image revision"
|
135
157
|
|
136
158
|
parameter "NAME ...",
|
137
|
-
"The name of the service (or task) to deploy
|
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
|
196
|
+
:flag, "Leave the task running after disconnect"
|
175
197
|
|
176
198
|
parameter "NAME",
|
177
|
-
"The name of the service (or task) to attach
|
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
|
-
|
195
|
-
|
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
|
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
|
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
|
@@ -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
|
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
|
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
|
-
|
39
|
-
logger.debug("
|
40
|
-
mkdir_p(
|
41
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
21
|
+
:flag, "generate a login password",
|
22
22
|
default: false
|
23
23
|
|
24
24
|
option ["-m", "--mfa"],
|
25
|
-
:flag, "setup a mfa device
|
25
|
+
:flag, "setup a mfa device",
|
26
26
|
default: false
|
27
27
|
|
28
28
|
option ["-k", "--key"],
|
29
|
-
:flag, "create access keys
|
29
|
+
:flag, "create access keys",
|
30
30
|
default: false
|
31
31
|
|
32
32
|
option ["-p", "--public-key"],
|
33
|
-
"PUBLIC_KEY", "add ssh public key
|
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
|
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
|
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}"]
|
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=[]
|
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
|
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})"]
|
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]
|
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]
|
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]
|
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"]
|
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
|
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,
|
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
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
|
data/lib/simplygenius/atmos.rb
CHANGED
@@ -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`
|
123
|
-
#
|
124
|
-
#
|
125
|
-
# Otherwise, disabling this functionality (value=true) means
|
126
|
-
# env/group combination will be independent and download all
|
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.
|
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:
|
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.
|
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
|