ecs_helper 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/ecs_helper.rb +2 -1
- data/lib/ecs_helper/client.rb +8 -0
- data/lib/ecs_helper/command.rb +2 -0
- data/lib/ecs_helper/command/deploy.rb +14 -84
- data/lib/ecs_helper/command/run_command.rb +145 -0
- data/lib/ecs_helper/task_definition_helper.rb +93 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9da09c69b8b7494c861ea3c278a10e86fbdcbf46a91d8b9253f997d899c33d7a
|
4
|
+
data.tar.gz: 4a47644247bd3d6fe9d6a31f58ad3734ea9387f1f70698a4aa89d92d7c64fbee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cab278533bc6ea72f9847e574beb37c731a9e913739e1956b42d50fe0b7fcfb40bef0f74d53f7430b764b0e85b2ab986922d81b8753863ca1f04e9859905838
|
7
|
+
data.tar.gz: a1d216b96efaf72fd04e864d4ba795ed84eb2c429fc3f435098c1347f49e0992b16c6467e6ad6dc761dfb794e19a2208c454f9d8cd1213613a4081cae6c82891
|
data/lib/ecs_helper.rb
CHANGED
@@ -10,9 +10,10 @@ class ECSHelper
|
|
10
10
|
autoload :CommonHelper, 'ecs_helper/common_helper'
|
11
11
|
autoload :ClusterHelper, 'ecs_helper/cluster_helper'
|
12
12
|
autoload :ServiceHelper, 'ecs_helper/service_helper'
|
13
|
+
autoload :TaskDefinitionHelper, 'ecs_helper/task_definition_helper'
|
13
14
|
autoload :Command, 'ecs_helper/command'
|
14
15
|
|
15
|
-
def_delegators :client, :task_definitions, :clusters, :services, :tasks, :repositories, :repositories, :task_definition
|
16
|
+
def_delegators :client, :task_definitions, :clusters, :services, :tasks, :repositories, :repositories, :task_definition, :run_task
|
16
17
|
def_delegators :common_helper, :version, :branch, :environment, :project, :application
|
17
18
|
def_delegators :cluster_helper, :current_cluster, :clusters
|
18
19
|
def_delegators :service_helper, :current_service, :services, :update_service
|
data/lib/ecs_helper/client.rb
CHANGED
@@ -48,6 +48,14 @@ class ECSHelper::Client
|
|
48
48
|
ecs.update_service(params)
|
49
49
|
end
|
50
50
|
|
51
|
+
def run_task(params = {})
|
52
|
+
ecs.run_task(params).tasks[0]
|
53
|
+
end
|
54
|
+
|
55
|
+
def describe_tasks(params = {})
|
56
|
+
ecs.describe_tasks(params).tasks
|
57
|
+
end
|
58
|
+
|
51
59
|
# ECR
|
52
60
|
def private_repositories(params = {})
|
53
61
|
ecr.describe_repositories(params).repositories
|
data/lib/ecs_helper/command.rb
CHANGED
@@ -5,12 +5,14 @@ class ECSHelper::Command
|
|
5
5
|
autoload :Deploy, 'ecs_helper/command/deploy'
|
6
6
|
autoload :ExportImages, 'ecs_helper/command/export_images'
|
7
7
|
autoload :ECRLogin, 'ecs_helper/command/ecr_login'
|
8
|
+
autoload :RunCommand, 'ecs_helper/command/run_command'
|
8
9
|
|
9
10
|
CMD_MAPPING = {
|
10
11
|
"build_and_push" => BuildAndPush,
|
11
12
|
"deploy" => Deploy,
|
12
13
|
"export_images" => ExportImages,
|
13
14
|
"ecr_login" => ECRLogin,
|
15
|
+
"run_command" => RunCommand,
|
14
16
|
}
|
15
17
|
AVAILABLE_COMMANDS = CMD_MAPPING.keys
|
16
18
|
|
@@ -13,7 +13,7 @@ class ECSHelper::Command::Deploy < ECSHelper::Command::Base
|
|
13
13
|
opts.on("-a VALUE", "--application VALUE", "Set application name, if not specified will look at ENV['APPLICATION'], will be used to detect service and task definition") { |a| options[:application] = processEqual(a) }
|
14
14
|
opts.on("-e VALUE", "--environment VALUE", "Set environment, if not specified will look at ENV['ENVIRONMENT'], it there is empty will try to detect based on the branch") { |e| options[:environment] = processEqual(e) }
|
15
15
|
opts.on("-v VALUE", "--version VALUE", "Set version which will be applied to all containers in the task if tag is present in the repo") { |t| options[:version] = processEqual(t) }
|
16
|
-
opts.on("-
|
16
|
+
opts.on("-cl VALUE", "--cluster VALUE", "Set cluster name, could be autodetected if project and environment are specified") { |c| options[:cluster] = processEqual(c) }
|
17
17
|
opts.on("-s VALUE", "--service VALUE", "Set service, could be autodetected if application and environment are specified") { |s| options[:service] = processEqual(s) }
|
18
18
|
opts.on("-t VALUE", "--timeout VALUE", "Set timeout how long to wait until deployment finished") { |t| options[:timeout] = processEqual(t) }
|
19
19
|
end
|
@@ -21,22 +21,30 @@ class ECSHelper::Command::Deploy < ECSHelper::Command::Base
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def run
|
24
|
+
task_definition_helper = TaskDefinitionHelper.new(helper, service)
|
25
|
+
service_task_definition = task_definition_helper.service_task_definition
|
26
|
+
new_task_definition_hash = task_definition_helper.new_task_definition_hash
|
27
|
+
new_task_definition = task_definition_helper.register_task_definition(new_task_definition_hash)
|
24
28
|
log("Command", type)
|
25
29
|
log("Options", options)
|
26
30
|
log("Environment", environment)
|
27
31
|
log("Cluster", cluster_arn)
|
28
32
|
log("Service", service_arn)
|
29
33
|
log("Version", version)
|
30
|
-
log("Service task definition", task_definition_arn)
|
31
|
-
log("Containers", pretty_container_definitions)
|
34
|
+
log("Service task definition", service_task_definition.task_definition_arn)
|
35
|
+
log("Containers", task_definition_helper.pretty_container_definitions)
|
32
36
|
log("New task definition", new_task_definition.task_definition_arn)
|
33
|
-
update_service && log("Update service", "Service task definition was updated")
|
37
|
+
update_service(new_task_definition.task_definition_arn) && log("Update service", "Service task definition was updated")
|
34
38
|
log("Waiting for deployment...")
|
35
39
|
wait_for_deployment && log("Success", "Application was succesfully deployed", :cyan)
|
36
40
|
end
|
37
41
|
|
42
|
+
def update_service(task_definition_arn)
|
43
|
+
helper.update_service(cluster_arn, service_arn, task_definition_arn)
|
44
|
+
helper.client.deregister_task_definition(task_definition: task_definition_arn)
|
45
|
+
end
|
46
|
+
|
38
47
|
def wait_for_deployment(time = 0)
|
39
|
-
service = helper.client.describe_service(cluster_arn, service_arn)
|
40
48
|
return true if service.deployments.count == 1
|
41
49
|
error("Deployment timeout (#{timeout})") if time > timeout
|
42
50
|
sleep STEP
|
@@ -66,84 +74,6 @@ class ECSHelper::Command::Deploy < ECSHelper::Command::Base
|
|
66
74
|
end
|
67
75
|
|
68
76
|
def service
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
def task_definition_arn
|
73
|
-
service.task_definition
|
74
|
-
end
|
75
|
-
|
76
|
-
def task_definition
|
77
|
-
@task_definition ||= helper.client.describe_task_definition(task_definition_arn)
|
78
|
-
end
|
79
|
-
|
80
|
-
def container_definitions
|
81
|
-
task_definition.container_definitions
|
82
|
-
end
|
83
|
-
|
84
|
-
def repositories
|
85
|
-
@repositories ||= client.private_repositories
|
86
|
-
end
|
87
|
-
|
88
|
-
def version_image(repo)
|
89
|
-
client.describe_images({repository_name: repo.repository_name, image_ids: [image_tag: version]})
|
90
|
-
rescue
|
91
|
-
nil
|
92
|
-
end
|
93
|
-
|
94
|
-
def new_task_definition
|
95
|
-
@new_task_definition ||= begin
|
96
|
-
attributes_to_remove = list = [:task_definition_arn, :revision, :status, :requires_attributes, :compatibilities, :registered_at, :registered_by]
|
97
|
-
new_task_definition_attributes = task_definition.to_hash
|
98
|
-
.reject { |k,v| attributes_to_remove.include?(k.to_sym) }
|
99
|
-
.merge(container_definitions: new_container_definitions)
|
100
|
-
helper.client.register_task_definition(new_task_definition_attributes)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def container_definition_to_ecr(cd)
|
105
|
-
repo = repo_for(cd.name)
|
106
|
-
is_ecr = cd.image.include?(ecr_base)
|
107
|
-
image = repo && version_image(repo)
|
108
|
-
should_update = is_ecr && repo && image
|
109
|
-
[repo, is_ecr, image, should_update]
|
110
|
-
end
|
111
|
-
|
112
|
-
def new_container_definitions
|
113
|
-
container_definitions.map do |cd|
|
114
|
-
repo, is_ecr, image, should_be_updated = container_definition_to_ecr(cd)
|
115
|
-
cd.image = "#{repo.repository_uri}:#{version}" if should_be_updated
|
116
|
-
cd.to_hash
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def pretty_container_definitions
|
121
|
-
container_definitions.map do |cd|
|
122
|
-
repo, is_ecr, image, should_be_updated = container_definition_to_ecr(cd)
|
123
|
-
[
|
124
|
-
cd.name,
|
125
|
-
cd.image,
|
126
|
-
is_ecr ? "ECR image" : "Not a ECR image",
|
127
|
-
repo ? "Repo #{repo.repository_name}" : "Repo not found",
|
128
|
-
image ? "Image version #{version}" : "Image version #{version} not found",
|
129
|
-
should_be_updated ? "Will be updated" : "Not applicable"
|
130
|
-
].join(' | ')
|
131
|
-
end.join("\n")
|
132
|
-
end
|
133
|
-
|
134
|
-
def repo_for(name)
|
135
|
-
repositories.find do |r|
|
136
|
-
uri = r.repository_uri
|
137
|
-
uri.include?(helper.application) && uri.include?(helper.project) && uri.include?(name)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
def ecr_base
|
142
|
-
repositories.first.repository_uri.split('/').first
|
143
|
-
end
|
144
|
-
|
145
|
-
def update_service
|
146
|
-
helper.update_service(cluster_arn, service_arn, new_task_definition.task_definition_arn)
|
147
|
-
helper.client.deregister_task_definition(task_definition: task_definition.task_definition_arn)
|
77
|
+
helper.client.describe_service(cluster_arn, service_arn)
|
148
78
|
end
|
149
79
|
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'terrapin'
|
2
|
+
|
3
|
+
class ECSHelper::Command::RunCommand < ECSHelper::Command::Base
|
4
|
+
attr_accessor :repositories, :task_definition, :new_task_definition, :service
|
5
|
+
DEFAULT_TIMEOUT = 300
|
6
|
+
STEP = 5
|
7
|
+
|
8
|
+
def cmd_option_parser
|
9
|
+
options = {}
|
10
|
+
parser = ::OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: ecs_helper run_command [options]"
|
12
|
+
opts.on("-p VALUE", "--project VALUE", "Set project name, if not specified will look at ENV['PROJECT'], will be used to detect cluster") { |p| options[:project] = processEqual(p) }
|
13
|
+
opts.on("-a VALUE", "--application VALUE", "Set application name, if not specified will look at ENV['APPLICATION'], will be used to detect service and task definition") { |a| options[:application] = processEqual(a) }
|
14
|
+
opts.on("-e VALUE", "--environment VALUE", "Set environment, if not specified will look at ENV['ENVIRONMENT'], it there is empty will try to detect based on the branch") { |e| options[:environment] = processEqual(e) }
|
15
|
+
opts.on("-v VALUE", "--version VALUE", "Set version which will be applied to all containers in the task if tag is present in the repo") { |t| options[:version] = processEqual(t) }
|
16
|
+
opts.on("--cluster VALUE", "Set cluster name, could be autodetected if project and environment are specified") { |c| options[:cluster] = processEqual(c) }
|
17
|
+
opts.on("-s VALUE", "--service VALUE", "Set service, could be autodetected if application and environment are specified") { |s| options[:service] = processEqual(s) }
|
18
|
+
opts.on("-t VALUE", "--timeout VALUE", "Set timeout how long to wait until deployment finished") { |t| options[:timeout] = processEqual(t) }
|
19
|
+
opts.on("--command VALUE", "Set command, should not demonize container") { |c| options[:command] = processEqual(c) }
|
20
|
+
opts.on("-n VALUE", "--name VALUE", "Set name (will be used for task definition name and log prefix") { |l| options[:name] = processEqual(l) }
|
21
|
+
opts.on("--container-name VALUE", "Set container name (default is the first container") { |cn| options[:container_name] = processEqual(cn) }
|
22
|
+
end
|
23
|
+
[parser, options]
|
24
|
+
end
|
25
|
+
|
26
|
+
def required
|
27
|
+
[:name, :command]
|
28
|
+
end
|
29
|
+
|
30
|
+
def run
|
31
|
+
task_definition_helper = ECSHelper::TaskDefinitionHelper.new(helper, service)
|
32
|
+
service_task_definition = task_definition_helper.service_task_definition
|
33
|
+
new_task_definition_hash = task_definition_helper.new_task_definition_hash
|
34
|
+
custom_task_definition_hash = custom_task_definition(new_task_definition_hash)
|
35
|
+
custom_task_definition = task_definition_helper.register_task_definition(custom_task_definition_hash)
|
36
|
+
|
37
|
+
log("Command", type)
|
38
|
+
log("Options", options)
|
39
|
+
log("Environment", environment)
|
40
|
+
log("Cluster", cluster_arn)
|
41
|
+
log("Service", service_arn)
|
42
|
+
log("Version", version)
|
43
|
+
log("New task definition", custom_task_definition.task_definition_arn)
|
44
|
+
task = run_task(custom_task_definition.task_definition_arn)
|
45
|
+
log("Start task", "Task #{task.task_arn} was started")
|
46
|
+
log("Waiting for task job...")
|
47
|
+
wait_for_task(task.task_arn) && log("Success", "Task finished successfully", :cyan)
|
48
|
+
end
|
49
|
+
|
50
|
+
def run_task(task_definition_arn)
|
51
|
+
helper.client.run_task({
|
52
|
+
cluster: cluster_arn,
|
53
|
+
task_definition: task_definition_arn,
|
54
|
+
network_configuration: service.network_configuration.to_hash,
|
55
|
+
launch_type: service.launch_type
|
56
|
+
})
|
57
|
+
end
|
58
|
+
|
59
|
+
def task(arn)
|
60
|
+
helper.client.describe_tasks({ cluster: cluster_arn, tasks: [arn] })[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
def wait_for_task(task_arn, time = 0)
|
64
|
+
task = task(task_arn)
|
65
|
+
container = task.containers[0];
|
66
|
+
log("container: #{container.name}, time: #{time}, timeout: #{timeout}, status: #{container.last_status}, exit_code: #{container.exit_code || 'NONE'}")
|
67
|
+
if container.last_status == "STOPPED"
|
68
|
+
return true if container.exit_code == 0
|
69
|
+
error("Task #{task_arn} finished with exit code #{container.exit_code}")
|
70
|
+
end
|
71
|
+
|
72
|
+
error("Task run timeout (#{timeout})") if time > timeout
|
73
|
+
sleep STEP
|
74
|
+
wait_for_task(task_arn, time + STEP)
|
75
|
+
end
|
76
|
+
|
77
|
+
def custom_task_definition(hash)
|
78
|
+
hash.merge({
|
79
|
+
container_definitions: new_container_definition(hash),
|
80
|
+
family: "#{hash[:family]}-#{name}",
|
81
|
+
})
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def new_container_definition(hash)
|
87
|
+
cds = hash[:container_definitions]
|
88
|
+
cds = [cds] if cds.is_a?(Hash)
|
89
|
+
cd = container_name ? cds.find {|cd| cd[:name] === container_name} : cds.first
|
90
|
+
error("Container not found") unless cd
|
91
|
+
new_cd = cd.merge({
|
92
|
+
command: command,
|
93
|
+
log_configuration: new_log_configuration(cd[:log_configuration]),
|
94
|
+
name: "#{cd[:name]}-#{name}"
|
95
|
+
})
|
96
|
+
[new_cd]
|
97
|
+
end
|
98
|
+
|
99
|
+
def new_log_configuration(log_configuration)
|
100
|
+
options = log_configuration[:options]
|
101
|
+
prefix = options["awslogs-stream-prefix"]
|
102
|
+
new_prefix = "#{prefix}-#{name}"
|
103
|
+
log_configuration.merge(options: options.merge("awslogs-stream-prefix" => new_prefix))
|
104
|
+
end
|
105
|
+
|
106
|
+
def command
|
107
|
+
['bash', '-c', "#{options[:command]}"]
|
108
|
+
end
|
109
|
+
|
110
|
+
def environment
|
111
|
+
helper.environment
|
112
|
+
end
|
113
|
+
|
114
|
+
def cluster_arn
|
115
|
+
helper.current_cluster
|
116
|
+
end
|
117
|
+
|
118
|
+
def service_arn
|
119
|
+
helper.current_service
|
120
|
+
end
|
121
|
+
|
122
|
+
def version
|
123
|
+
options[:version] || helper.version
|
124
|
+
end
|
125
|
+
|
126
|
+
def timeout
|
127
|
+
options[:timeout] || DEFAULT_TIMEOUT
|
128
|
+
end
|
129
|
+
|
130
|
+
def service
|
131
|
+
helper.client.describe_service(cluster_arn, service_arn)
|
132
|
+
end
|
133
|
+
|
134
|
+
def name
|
135
|
+
options[:name]
|
136
|
+
end
|
137
|
+
|
138
|
+
def service
|
139
|
+
helper.client.describe_service(cluster_arn, service_arn)
|
140
|
+
end
|
141
|
+
|
142
|
+
def container_name
|
143
|
+
options[:container_name]
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'aws-sdk-ecs'
|
2
|
+
|
3
|
+
class ECSHelper::TaskDefinitionHelper
|
4
|
+
attr_accessor :helper, :service, :service_task_definition, :repositories, :new_task_definition_hash
|
5
|
+
def initialize(helper, service)
|
6
|
+
@helper = helper
|
7
|
+
@service = service
|
8
|
+
end
|
9
|
+
|
10
|
+
def service_task_definition
|
11
|
+
@service_task_definition ||= helper.client.describe_task_definition(service.task_definition)
|
12
|
+
end
|
13
|
+
|
14
|
+
def container_definitions
|
15
|
+
service_task_definition.container_definitions
|
16
|
+
end
|
17
|
+
|
18
|
+
def pretty_container_definitions
|
19
|
+
container_definitions.map do |cd|
|
20
|
+
repo, is_ecr, image, should_be_updated = container_definition_to_ecr(cd)
|
21
|
+
[
|
22
|
+
cd.name,
|
23
|
+
cd.image,
|
24
|
+
is_ecr ? "ECR image" : "Not a ECR image",
|
25
|
+
repo ? "Repo #{repo.repository_name}" : "Repo not found",
|
26
|
+
image ? "Image version #{version}" : "Image version #{version} not found",
|
27
|
+
should_be_updated ? "Will be updated" : "Not applicable"
|
28
|
+
].join(' | ')
|
29
|
+
end.join("\n")
|
30
|
+
end
|
31
|
+
|
32
|
+
def register_task_definition(hash)
|
33
|
+
helper.client.register_task_definition(hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def new_task_definition_hash
|
37
|
+
attributes_to_remove = list = [:task_definition_arn, :revision, :status, :requires_attributes, :compatibilities, :registered_at, :registered_by]
|
38
|
+
service_task_definition.to_hash
|
39
|
+
.reject { |k,v| attributes_to_remove.include?(k.to_sym) }
|
40
|
+
.merge(container_definitions: new_container_definitions)
|
41
|
+
end
|
42
|
+
|
43
|
+
def container_definition_to_ecr(cd)
|
44
|
+
repo = repo_for(cd.name)
|
45
|
+
is_ecr = cd.image.include?(ecr_base)
|
46
|
+
image = repo && version_image(repo)
|
47
|
+
should_update = is_ecr && repo && image
|
48
|
+
[repo, is_ecr, image, should_update]
|
49
|
+
end
|
50
|
+
|
51
|
+
def new_container_definitions
|
52
|
+
container_definitions.map do |cd|
|
53
|
+
repo, is_ecr, image, should_be_updated = container_definition_to_ecr(cd)
|
54
|
+
cd.image = "#{repo.repository_uri}:#{version}" if should_be_updated
|
55
|
+
cd.to_hash
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def container_definition_to_ecr(cd)
|
62
|
+
repo = repo_for(cd.name)
|
63
|
+
is_ecr = cd.image.include?(ecr_base)
|
64
|
+
image = repo && version_image(repo)
|
65
|
+
should_update = is_ecr && repo && image
|
66
|
+
[repo, is_ecr, image, should_update]
|
67
|
+
end
|
68
|
+
|
69
|
+
def repo_for(name)
|
70
|
+
repositories.find do |r|
|
71
|
+
uri = r.repository_uri
|
72
|
+
uri.include?(helper.application) && uri.include?(helper.project) && uri.include?(name)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def repositories
|
77
|
+
@repositories ||= helper.client.private_repositories
|
78
|
+
end
|
79
|
+
|
80
|
+
def ecr_base
|
81
|
+
repositories.first.repository_uri.split('/').first
|
82
|
+
end
|
83
|
+
|
84
|
+
def version_image(repo)
|
85
|
+
client.describe_images({repository_name: repo.repository_name, image_ids: [image_tag: version]})
|
86
|
+
rescue
|
87
|
+
nil
|
88
|
+
end
|
89
|
+
|
90
|
+
def version
|
91
|
+
helper.options[:version] || helper.version
|
92
|
+
end
|
93
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ecs_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Artem Petrov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-ecs
|
@@ -147,9 +147,11 @@ files:
|
|
147
147
|
- lib/ecs_helper/command/deploy.rb
|
148
148
|
- lib/ecs_helper/command/ecr_login.rb
|
149
149
|
- lib/ecs_helper/command/export_images.rb
|
150
|
+
- lib/ecs_helper/command/run_command.rb
|
150
151
|
- lib/ecs_helper/common_helper.rb
|
151
152
|
- lib/ecs_helper/logging.rb
|
152
153
|
- lib/ecs_helper/service_helper.rb
|
154
|
+
- lib/ecs_helper/task_definition_helper.rb
|
153
155
|
homepage: https://rubygems.org/gems/ecs_helper
|
154
156
|
licenses:
|
155
157
|
- MIT
|