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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f4e40c9c0050075171080514f957eeef76fce51e292c5305d2003005326ad1bb
4
- data.tar.gz: f48a33a223c127b561f7e639834fa59c0b7c0ad96f42fc661af062e50ef6f439
3
+ metadata.gz: 9da09c69b8b7494c861ea3c278a10e86fbdcbf46a91d8b9253f997d899c33d7a
4
+ data.tar.gz: 4a47644247bd3d6fe9d6a31f58ad3734ea9387f1f70698a4aa89d92d7c64fbee
5
5
  SHA512:
6
- metadata.gz: 849243dae8979adaf2ee254edbe49142af2a96e32143472653f124030c8f5389d278ae55b26c063b6b05793f544e7d2183424d0630b0680761371e3dfb7b10d6
7
- data.tar.gz: e4cc9793f2962554bfa56ccad5d0c4f7045eb098ff5d98be470be58dc97a03fec07966d23601085971baa94594c73698c603796dffdd85e28988717562aec322
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
@@ -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
@@ -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("-c VALUE", "--cluster VALUE", "Set cluster name, could be autodetected if project and environment are specified") { |c| options[:cluster] = processEqual(c) }
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
- @service ||= helper.client.describe_service(cluster_arn, service_arn)
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.10
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-18 00:00:00.000000000 Z
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