simplygenius-atmos 0.11.3 → 0.11.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/simplygenius/atmos/commands/container.rb +45 -21
- data/lib/simplygenius/atmos/commands/user.rb +1 -1
- data/lib/simplygenius/atmos/config.rb +0 -2
- data/lib/simplygenius/atmos/providers/aws/container_manager.rb +82 -1
- data/lib/simplygenius/atmos/settings_hash.rb +11 -7
- data/lib/simplygenius/atmos/version.rb +1 -1
- data/templates/new/config/atmos/runtime.yml +45 -0
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ca7971744542f8e7e8b9892a57425edbef56c418b22617295f539a4e737a62d
|
4
|
+
data.tar.gz: 7a2e7501ec94b617eb0bb3c1d91a37b76884ca57ebc079d4a14e367b41827063
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4fff280b4474c41e9329bc49ecfdd7ae215fbb2fd33b45161e94056126710bdca0d8461379029ed45ae23672724cce10cd61d7b79413190738d8b8a3121ad42d
|
7
|
+
data.tar.gz: 6d9801ed068c5c007d67e7f0c086134db4aa396a7e6b9c0a983cfa2ac3711ac7c4bd8eeb6092b82011362ed25d79a4bb9f7dfce243470ce928232a256f88efee
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.11.4 (11/27/2019)
|
2
|
+
-------------------
|
3
|
+
|
4
|
+
* add the ability to spawn a console for any service container [0d1764e](https://github.com/simplygenius/atmos/commit/0d1764e)
|
5
|
+
* allow escaping atmos interpolations [3d8b59e](https://github.com/simplygenius/atmos/commit/3d8b59e)
|
6
|
+
|
7
|
+
|
1
8
|
0.11.3 (11/12/2019)
|
2
9
|
-------------------
|
3
10
|
|
@@ -14,14 +14,14 @@ module SimplyGenius
|
|
14
14
|
"Manages containers in the cloud provider"
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
option ["-c", "--cluster"],
|
18
|
+
"CLUSTER", "The cluster name\n",
|
19
|
+
required: true
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
required: true
|
21
|
+
option ["-r", "--role"],
|
22
|
+
"ROLE", "The role to assume when deploying\n"
|
22
23
|
|
23
|
-
|
24
|
-
"ROLE", "The role to assume when deploying\n"
|
24
|
+
subcommand "push", "Only push a container image without activating it" do
|
25
25
|
|
26
26
|
option ["-i", "--image"],
|
27
27
|
"IMAGE", "The local container image to deploy\nDefaults to service/task name"
|
@@ -54,15 +54,8 @@ module SimplyGenius
|
|
54
54
|
|
55
55
|
subcommand "activate", "Activate a container that has already been pushed" do
|
56
56
|
|
57
|
-
option ["-c", "--cluster"],
|
58
|
-
"CLUSTER", "The cluster name\n",
|
59
|
-
required: true
|
60
|
-
|
61
|
-
option ["-r", "--role"],
|
62
|
-
"ROLE", "The role to assume when deploying\n"
|
63
|
-
|
64
57
|
option ["-v", "--revision"],
|
65
|
-
"REVISION", "Use the given revision of the pushed image
|
58
|
+
"REVISION", "Use the given revision of the pushed image\nto activate\n"
|
66
59
|
|
67
60
|
option ["-l", "--list"],
|
68
61
|
:flag, "List the most recent pushed images\n"
|
@@ -122,13 +115,6 @@ module SimplyGenius
|
|
122
115
|
|
123
116
|
subcommand "deploy", "Push and activate a container" do
|
124
117
|
|
125
|
-
option ["-c", "--cluster"],
|
126
|
-
"CLUSTER", "The cluster name\n",
|
127
|
-
required: true
|
128
|
-
|
129
|
-
option ["-r", "--role"],
|
130
|
-
"ROLE", "The role to assume when deploying\n"
|
131
|
-
|
132
118
|
option ["-i", "--image"],
|
133
119
|
"IMAGE", "The local container image to deploy\nDefaults to service/task name"
|
134
120
|
|
@@ -164,6 +150,44 @@ module SimplyGenius
|
|
164
150
|
end
|
165
151
|
end
|
166
152
|
|
153
|
+
subcommand "console", "Spawn a console and attach to it" do
|
154
|
+
|
155
|
+
option ["-p", "--persist"],
|
156
|
+
:flag, "Leave the task running after disconnect\n"
|
157
|
+
|
158
|
+
parameter "NAME",
|
159
|
+
"The name of the service (or task) to attach\nthe console to"
|
160
|
+
|
161
|
+
def execute
|
162
|
+
Atmos.config.provider.auth_manager.authenticate(ENV, role: role) do |auth_env|
|
163
|
+
ClimateControl.modify(auth_env) do
|
164
|
+
mgr = Atmos.config.provider.container_manager
|
165
|
+
remote_command = Array(Atmos.config['atmos.container.console.remote_command'])
|
166
|
+
remote_persist_command = Array(Atmos.config['atmos.container.console.remote_persist_command'])
|
167
|
+
log_pattern = Atmos.config['atmos.container.console.remote_log_pattern']
|
168
|
+
local_command = Atmos.config['atmos.container.console.local_command']
|
169
|
+
|
170
|
+
cmd = persist? ? remote_persist_command : remote_command
|
171
|
+
logger.debug "Running remote command: #{cmd.join(" ")}"
|
172
|
+
result = mgr.run_task(cluster, name, command: cmd, waiter_log_pattern: log_pattern)
|
173
|
+
logger.debug "Run task result: #{result}"
|
174
|
+
begin
|
175
|
+
match = result[:log_match]
|
176
|
+
local_command = local_command.collect {|c| match.names.each {|n| c = c.gsub("<#{n}>", match[n]) }; c }
|
177
|
+
system(*local_command)
|
178
|
+
ensure
|
179
|
+
if persist?
|
180
|
+
logger.info "Console disconnected, you can reconnect with: #{local_command.join(" ")}"
|
181
|
+
else
|
182
|
+
logger.info "Console complete, stopping task"
|
183
|
+
mgr.stop_task(cluster, result[:task_id])
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
167
191
|
end
|
168
192
|
|
169
193
|
end
|
@@ -14,7 +14,7 @@ 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\nresources",
|
18
18
|
default: false
|
19
19
|
|
20
20
|
option ["-l", "--login"],
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative '../../../atmos'
|
2
2
|
require 'aws-sdk-ecs'
|
3
3
|
require 'aws-sdk-ecr'
|
4
|
+
require 'aws-sdk-cloudwatchlogs'
|
4
5
|
require 'open3'
|
5
6
|
|
6
7
|
module SimplyGenius
|
@@ -159,7 +160,87 @@ module SimplyGenius
|
|
159
160
|
return result
|
160
161
|
end
|
161
162
|
|
162
|
-
|
163
|
+
def run_task(cluster, name, command:, waiter_log_pattern: nil, launch_type: "FARGATE")
|
164
|
+
result = {}
|
165
|
+
|
166
|
+
ecs = ::Aws::ECS::Client.new
|
167
|
+
resp = nil
|
168
|
+
|
169
|
+
task_opts = {
|
170
|
+
count: 1,
|
171
|
+
cluster: cluster,
|
172
|
+
task_definition: name,
|
173
|
+
launch_type: launch_type,
|
174
|
+
overrides: {container_overrides: [{name: name, command: command}]}
|
175
|
+
}
|
176
|
+
|
177
|
+
defn_arn = nil
|
178
|
+
resp = ecs.describe_services(cluster: cluster, services: [name])
|
179
|
+
if resp.services.size > 0
|
180
|
+
svc = resp.services.first
|
181
|
+
task_opts[:launch_type] = svc.launch_type
|
182
|
+
task_opts[:network_configuration] = svc.network_configuration.to_h
|
183
|
+
defn_arn = svc.task_definition
|
184
|
+
logger.info "Running service task as '#{task_opts[:launch_type]}'"
|
185
|
+
else
|
186
|
+
resp = ecs.list_task_definitions(family_prefix: name, sort: 'DESC')
|
187
|
+
defn_arn = resp.task_definition_arns.first
|
188
|
+
logger.info "Running task as '#{task_opts[:launch_type]}'"
|
189
|
+
end
|
190
|
+
|
191
|
+
resp = ecs.describe_task_definition(task_definition: defn_arn)
|
192
|
+
defn = resp.task_definition
|
193
|
+
raise "Invalid Launch type '#{launch_type}'" unless (defn.requires_compatibilities + defn.compatibilities).include?(launch_type)
|
194
|
+
|
195
|
+
log_config = defn.container_definitions.first.log_configuration
|
196
|
+
log_group = nil
|
197
|
+
log_stream_prefix = nil
|
198
|
+
if log_config && log_config.log_driver == "awslogs"
|
199
|
+
log_group = log_config.options["awslogs-group"]
|
200
|
+
log_stream_prefix = log_config.options["awslogs-stream-prefix"]
|
201
|
+
end
|
202
|
+
if waiter_log_pattern && log_group.nil?
|
203
|
+
logger.error "Cannot wait on a log unless task definition uses cloudwatch for logging"
|
204
|
+
waiter_log_pattern = nil
|
205
|
+
end
|
206
|
+
|
207
|
+
resp = ecs.run_task(**task_opts)
|
208
|
+
task_arn = result[:task_arn] = resp.tasks.first.task_arn
|
209
|
+
task_id = result[:task_id] = task_arn.split('/').last
|
210
|
+
|
211
|
+
logger.info "Waiting for task to start"
|
212
|
+
ecs.wait_until(:tasks_running, cluster: cluster, tasks: [task_id])
|
213
|
+
|
214
|
+
if waiter_log_pattern
|
215
|
+
cwl = ::Aws::CloudWatchLogs::Client.new
|
216
|
+
|
217
|
+
waiter_regexp = Regexp.new(waiter_log_pattern)
|
218
|
+
log_stream = "#{log_stream_prefix}/#{name}/#{task_id}"
|
219
|
+
logger.info "Task started, looking for log pattern in group=#{log_group} stream=#{log_stream}"
|
220
|
+
log_token = nil
|
221
|
+
10.times do
|
222
|
+
resp = cwl.get_log_events(log_group_name: log_group, log_stream_name: log_stream, start_from_head: true, next_token: log_token)
|
223
|
+
resp.events.each do |e|
|
224
|
+
logger.debug("Task log #{e.timestamp}: #{e.message}")
|
225
|
+
if e.message =~ waiter_regexp
|
226
|
+
result[:log_match] = Regexp.last_match
|
227
|
+
return result # return, not break due to doubly nested iterator
|
228
|
+
end
|
229
|
+
end
|
230
|
+
log_token = resp.next_forward_token
|
231
|
+
sleep 1
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
return result
|
236
|
+
end
|
237
|
+
|
238
|
+
def stop_task(cluster, task)
|
239
|
+
ecs = ::Aws::ECS::Client.new
|
240
|
+
resp = ecs.stop_task(cluster: cluster, task: task)
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
163
244
|
|
164
245
|
def run(*args, **opts)
|
165
246
|
logger.debug("Running: #{args}")
|
@@ -12,7 +12,7 @@ module SimplyGenius
|
|
12
12
|
disable_warnings
|
13
13
|
|
14
14
|
PATH_PATTERN = /[\.\[\]]/
|
15
|
-
INTERP_PATTERN = /(
|
15
|
+
INTERP_PATTERN = /(\#?\#\{([^\}]+)\})/
|
16
16
|
|
17
17
|
attr_accessor :_root_, :error_resolver, :enable_expansion
|
18
18
|
|
@@ -84,12 +84,16 @@ module SimplyGenius
|
|
84
84
|
result.scan(INTERP_PATTERN).each do |substr, statement|
|
85
85
|
# TODO: add an explicit check for cycles instead of relying on Stack error
|
86
86
|
begin
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
87
|
+
if substr.start_with?('##')
|
88
|
+
val = substr[1..-1]
|
89
|
+
else
|
90
|
+
# TODO: be consistent with dot notation between eval and
|
91
|
+
# notation_get. eval ends up calling Hashie method_missing,
|
92
|
+
# which returns nil if a key doesn't exist, causing a nil
|
93
|
+
# exception for next item in chain, while notation_get returns
|
94
|
+
# nil gracefully for the entire chain (preferred)
|
95
|
+
val = eval(statement, binding, __FILE__)
|
96
|
+
end
|
93
97
|
rescue SystemStackError => e
|
94
98
|
raise ConfigInterpolationError.new(format_error("Cycle in interpolated config", substr))
|
95
99
|
rescue StandardError => e
|
@@ -64,6 +64,51 @@ atmos:
|
|
64
64
|
# a GUI notification
|
65
65
|
force_inline: false
|
66
66
|
|
67
|
+
# Configure the container components accessible with 'atmos container ....'
|
68
|
+
container:
|
69
|
+
# Configuration for the console subcommand
|
70
|
+
# For this to work, your service container needs to have a recent (>= 2.4)
|
71
|
+
# tmate installed. For example in a debian container:
|
72
|
+
#
|
73
|
+
# # Install locales package for tmate
|
74
|
+
# RUN apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -q -y locales
|
75
|
+
#
|
76
|
+
# # To set utf-8 locale for tmate
|
77
|
+
# RUN sed -i -e 's/# \(en_US\.UTF-8 .*\)/\1/' /etc/locale.gen && \
|
78
|
+
# dpkg-reconfigure --frontend=noninteractive locales && \
|
79
|
+
# update-locale LANG=en_US.UTF-8
|
80
|
+
# ENV LANG en_US.UTF-8
|
81
|
+
#
|
82
|
+
# # Install tmate
|
83
|
+
# RUN curl -Lo /tmp/tmate.tar.xz https://github.com/tmate-io/tmate/releases/download/2.4.0/tmate-2.4.0-static-linux-amd64.tar.xz && \
|
84
|
+
# cd /tmp && \
|
85
|
+
# tar xf /tmp/tmate.tar.xz && \
|
86
|
+
# mv tmate-2.4.0-static-linux-amd64/tmate /usr/bin/tmate && \
|
87
|
+
# rm -rf /tmp/tmate*
|
88
|
+
#
|
89
|
+
# # tmate needs ssh keys
|
90
|
+
# RUN ssh-keygen -f ~/.ssh/id_rsa -N '' -t rsa
|
91
|
+
#
|
92
|
+
console:
|
93
|
+
# The remote command to run when initiating a console (exits on disconnect)
|
94
|
+
remote_command:
|
95
|
+
- bash
|
96
|
+
- -c
|
97
|
+
- echo "set tmate-foreground-restart 0" > ~/.tmate.conf && tmate -F
|
98
|
+
# The remote command to run when initiating a console (persists on disconnect)
|
99
|
+
remote_persist_command:
|
100
|
+
- bash
|
101
|
+
- -c
|
102
|
+
- tmate -F
|
103
|
+
# The regexp to match against remote command output to extract any tokens
|
104
|
+
# needed for the client to connect. The regexp named groups (?<...>) get
|
105
|
+
# substituted within the client command (<...>)
|
106
|
+
remote_log_pattern: "^ssh session: ssh (?<token>\\w+)@nyc1.tmate.io$"
|
107
|
+
# The local command to run when initiating a console
|
108
|
+
local_command:
|
109
|
+
- ssh
|
110
|
+
- <token>@nyc1.tmate.io
|
111
|
+
|
67
112
|
# Configure terraform execution details
|
68
113
|
terraform:
|
69
114
|
# Disable module fetch from convenience plan/apply commands
|
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.
|
4
|
+
version: 0.11.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Conway
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-11-
|
11
|
+
date: 2019-11-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -416,6 +416,20 @@ dependencies:
|
|
416
416
|
- - ">="
|
417
417
|
- !ruby/object:Gem::Version
|
418
418
|
version: '0'
|
419
|
+
- !ruby/object:Gem::Dependency
|
420
|
+
name: aws-sdk-cloudwatchlogs
|
421
|
+
requirement: !ruby/object:Gem::Requirement
|
422
|
+
requirements:
|
423
|
+
- - ">="
|
424
|
+
- !ruby/object:Gem::Version
|
425
|
+
version: '0'
|
426
|
+
type: :runtime
|
427
|
+
prerelease: false
|
428
|
+
version_requirements: !ruby/object:Gem::Requirement
|
429
|
+
requirements:
|
430
|
+
- - ">="
|
431
|
+
- !ruby/object:Gem::Version
|
432
|
+
version: '0'
|
419
433
|
- !ruby/object:Gem::Dependency
|
420
434
|
name: os
|
421
435
|
requirement: !ruby/object:Gem::Requirement
|