ecs_helper 0.0.6 → 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: bc4a63fcf5c08e94f73e2531698b53a35ba0ecf6c93f3847829e0a0b844ecfd3
4
- data.tar.gz: 844e8665dd3b55fdb4776e309b59d62b61b26ae710f42c336d4fe2598af54118
3
+ metadata.gz: 9da09c69b8b7494c861ea3c278a10e86fbdcbf46a91d8b9253f997d899c33d7a
4
+ data.tar.gz: 4a47644247bd3d6fe9d6a31f58ad3734ea9387f1f70698a4aa89d92d7c64fbee
5
5
  SHA512:
6
- metadata.gz: '071923e4ed5313a85ffeae2a85613e66ef76fe643ed7dbdf72ab9e53d7051159df75592700ba31f7583257507ee9825dd54c25869a11d769433b300a90eadd52'
7
- data.tar.gz: 5e540f604ff4836c8309b5a146e9e5a1715086c2a3df7d834756b34acb4ba55f32d83f6f043427cf944443b4ca8b8b9ceae7507bce7c051c49ef0b6f0aad4eda
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
 
@@ -32,7 +32,6 @@ class ECSHelper::Command::BuildAndPush < ECSHelper::Command::Base
32
32
  def auth_public
33
33
  auth_cmd = Terrapin::CommandLine.new("aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws")
34
34
  auth_cmd.run
35
-
36
35
  end
37
36
 
38
37
  def auth_private
@@ -2,7 +2,7 @@ require 'terrapin'
2
2
 
3
3
  class ECSHelper::Command::Deploy < ECSHelper::Command::Base
4
4
  attr_accessor :repositories, :task_definition, :new_task_definition, :service
5
- TIMEOUT = 300
5
+ DEFAULT_TIMEOUT = 300
6
6
  STEP = 5
7
7
 
8
8
  def cmd_option_parser
@@ -12,32 +12,41 @@ class ECSHelper::Command::Deploy < ECSHelper::Command::Base
12
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
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
- opts.on("-t VALUE", "--tag VALUE", "Set tag which will be applied to all containers in the task if tag is present in the repo") { |t| options[:tag] = 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) }
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("-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
+ opts.on("-t VALUE", "--timeout VALUE", "Set timeout how long to wait until deployment finished") { |t| options[:timeout] = processEqual(t) }
18
19
  end
19
20
  [parser, options]
20
21
  end
21
22
 
22
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)
23
28
  log("Command", type)
24
29
  log("Options", options)
25
30
  log("Environment", environment)
26
31
  log("Cluster", cluster_arn)
27
32
  log("Service", service_arn)
28
- log("Tag", tag)
29
- log("Service task definition", task_definition_arn)
30
- log("Containers", pretty_container_definitions)
33
+ log("Version", version)
34
+ log("Service task definition", service_task_definition.task_definition_arn)
35
+ log("Containers", task_definition_helper.pretty_container_definitions)
31
36
  log("New task definition", new_task_definition.task_definition_arn)
32
- 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")
33
38
  log("Waiting for deployment...")
34
39
  wait_for_deployment && log("Success", "Application was succesfully deployed", :cyan)
35
40
  end
36
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
+
37
47
  def wait_for_deployment(time = 0)
38
- service = helper.client.describe_service(cluster_arn, service_arn)
39
48
  return true if service.deployments.count == 1
40
- error("Deployment timeout (#{TIMEOUT})") if time > TIMEOUT
49
+ error("Deployment timeout (#{timeout})") if time > timeout
41
50
  sleep STEP
42
51
  wait_for_deployment(time + STEP)
43
52
  end
@@ -56,89 +65,15 @@ class ECSHelper::Command::Deploy < ECSHelper::Command::Base
56
65
  helper.current_service
57
66
  end
58
67
 
59
- def tag
60
- options[:tag] || helper.version
61
- end
62
-
63
- def service
64
- @service ||= helper.client.describe_service(cluster_arn, service_arn)
65
- end
66
-
67
- def task_definition_arn
68
- service.task_definition
68
+ def version
69
+ options[:version] || helper.version
69
70
  end
70
71
 
71
- def task_definition
72
- @task_definition ||= helper.client.describe_task_definition(task_definition_arn)
72
+ def timeout
73
+ options[:timeout] || DEFAULT_TIMEOUT
73
74
  end
74
75
 
75
- def container_definitions
76
- task_definition.container_definitions
77
- end
78
-
79
- def repositories
80
- @repositories ||= client.repositories
81
- end
82
-
83
- def tag_image(repo)
84
- client.describe_images({repository_name: repo.repository_name, image_ids: [image_tag: tag]})
85
- rescue
86
- nil
87
- end
88
-
89
- def new_task_definition
90
- @new_task_definition ||= begin
91
- attributes_to_remove = list = [:task_definition_arn, :revision, :status, :requires_attributes, :compatibilities, :registered_at, :registered_by]
92
- new_task_definition_attributes = task_definition.to_hash
93
- .reject { |k,v| attributes_to_remove.include?(k.to_sym) }
94
- .merge(container_definitions: new_container_definitions)
95
- helper.client.register_task_definition(new_task_definition_attributes)
96
- end
97
- end
98
-
99
- def container_definition_to_ecr(cd)
100
- repo = repo_for(cd.name)
101
- is_ecr = cd.image.include?(ecr_base)
102
- image = repo && tag_image(repo)
103
- should_update = is_ecr && repo && image
104
- [repo, is_ecr, image, should_update]
105
- end
106
-
107
- def new_container_definitions
108
- container_definitions.map do |cd|
109
- repo, is_ecr, image, should_be_updated = container_definition_to_ecr(cd)
110
- cd.image = "#{repo.repository_uri}:#{tag}" if should_be_updated
111
- cd.to_hash
112
- end
113
- end
114
-
115
- def pretty_container_definitions
116
- container_definitions.map do |cd|
117
- repo, is_ecr, image, should_be_updated = container_definition_to_ecr(cd)
118
- [
119
- cd.name,
120
- cd.image,
121
- is_ecr ? "ECR image" : "Not a ECR image",
122
- repo ? "Repo #{repo.repository_name}" : "Repo not found",
123
- image ? "Image tag #{tag}" : "Image tag #{tag} not found",
124
- should_be_updated ? "Will be updated" : "Not applicable"
125
- ].join(' | ')
126
- end.join("\n")
127
- end
128
-
129
- def repo_for(name)
130
- repositories.find do |r|
131
- uri = r.repository_uri
132
- uri.include?(helper.application) && uri.include?(helper.project) && uri.include?(name)
133
- end
134
- end
135
-
136
- def ecr_base
137
- repositories.first.repository_uri.split('/').first
138
- end
139
-
140
- def update_service
141
- helper.update_service(cluster_arn, service_arn, new_task_definition.task_definition_arn)
142
- helper.client.deregister_task_definition(task_definition: task_definition.task_definition_arn)
76
+ def service
77
+ helper.client.describe_service(cluster_arn, service_arn)
143
78
  end
144
79
  end
@@ -18,12 +18,6 @@ class ECSHelper::Command::ExportImages < ECSHelper::Command::Base
18
18
  puts export_images
19
19
  end
20
20
 
21
- def auth
22
- auth_cmd = Terrapin::CommandLine.new("aws ecr get-login --no-include-email | sh")
23
- auth_cmd.run
24
- end
25
-
26
-
27
21
  private
28
22
 
29
23
  def project
@@ -35,7 +29,7 @@ class ECSHelper::Command::ExportImages < ECSHelper::Command::Base
35
29
  end
36
30
 
37
31
  def export_images
38
- variables = (['export'] + client.publicrepositories.map do |repo|
32
+ variables = (['export'] + client.private_repositories.map do |repo|
39
33
  container_name = repo.repository_name.scan(/#{project}-#{application}-(.*)/).flatten.first
40
34
  key = container_name.upcase.gsub("-", "_") + "_IMAGE"
41
35
  value = "#{repo.repository_uri}:#{helper.version}"
@@ -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.6
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-15 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