ecs_helper 0.0.10 → 0.0.12

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: 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