ufo 4.1.7 → 4.1.8

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: 75ec49e17bcba80691ed111954edc66403d8144536be56168665db85db974768
4
- data.tar.gz: f60ee60c3dd19a8ed44dd7788811c3003dc5d73f6276d5715a4a0c32fdcbcba4
3
+ metadata.gz: fbed0337ef427b9207e2519ea203529f4f2db33c8b3b8a2566e53ad88da9456b
4
+ data.tar.gz: c4f46be9a77ab2946db88193429b0c9317fd5b9c61b909c2861514312dbc894f
5
5
  SHA512:
6
- metadata.gz: 15bc1ff63ee2f7c9cf959f2ee2da0dba750a8447ffb3a40ad22703050b28160b57329b1b8ca6f716298b62dd44b457fdebf8519921bb03139e634b3de40761af
7
- data.tar.gz: e52d45d8e7c5900fb8c8bcc2851781bf94300f630eb5587629c1e612d187e3eb37526d26ec46296e7a35c1870db72d405216ced9811b1ebbd716a5990951e7ad
6
+ metadata.gz: 9e6cd3faba4289427dfbbdd1fc65785ad563bab135a9e3816b4094ba93a4c97392e3591bd0aeeed909759ceef1fc27cfced0bacf6be33896da90ceb052418f91
7
+ data.tar.gz: 0452d37d8a1e785ca5f9bf0d91995d16e575d61ca0d7563f6d17ea556ae35bb03f155fde9917efb1a83c73cce1dca852702a85191f952822935c4cae644dafa1
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [4.1.8]
7
+ - Merge pull request #59 from everplays/58-ability-to-wait-for-one-off-task-to-finish
8
+ - Merge pull request #60 from tongueroo/wait-exit-code
9
+
6
10
  ## [4.1.7]
7
11
  - add scheduling-strategy option #55 from tongueroo/scheduling-strategy
8
12
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ufo (4.1.7)
4
+ ufo (4.1.8)
5
5
  aws-sdk-cloudformation
6
6
  aws-sdk-cloudwatchlogs
7
7
  aws-sdk-ec2
@@ -19,35 +19,35 @@ PATH
19
19
  GEM
20
20
  remote: https://rubygems.org/
21
21
  specs:
22
- activesupport (5.2.1)
22
+ activesupport (5.2.1.1)
23
23
  concurrent-ruby (~> 1.0, >= 1.0.2)
24
24
  i18n (>= 0.7, < 2)
25
25
  minitest (~> 5.1)
26
26
  tzinfo (~> 1.1)
27
27
  aws-eventstream (1.0.1)
28
- aws-partitions (1.111.0)
29
- aws-sdk-cloudformation (1.11.0)
30
- aws-sdk-core (~> 3, >= 3.26.0)
28
+ aws-partitions (1.121.0)
29
+ aws-sdk-cloudformation (1.13.0)
30
+ aws-sdk-core (~> 3, >= 3.39.0)
31
31
  aws-sigv4 (~> 1.0)
32
- aws-sdk-cloudwatchlogs (1.10.0)
33
- aws-sdk-core (~> 3, >= 3.26.0)
32
+ aws-sdk-cloudwatchlogs (1.12.0)
33
+ aws-sdk-core (~> 3, >= 3.39.0)
34
34
  aws-sigv4 (~> 1.0)
35
- aws-sdk-core (3.38.0)
35
+ aws-sdk-core (3.42.0)
36
36
  aws-eventstream (~> 1.0)
37
37
  aws-partitions (~> 1.0)
38
38
  aws-sigv4 (~> 1.0)
39
39
  jmespath (~> 1.0)
40
- aws-sdk-ec2 (1.56.0)
41
- aws-sdk-core (~> 3, >= 3.26.0)
40
+ aws-sdk-ec2 (1.62.0)
41
+ aws-sdk-core (~> 3, >= 3.39.0)
42
42
  aws-sigv4 (~> 1.0)
43
- aws-sdk-ecr (1.8.0)
44
- aws-sdk-core (~> 3, >= 3.26.0)
43
+ aws-sdk-ecr (1.9.0)
44
+ aws-sdk-core (~> 3, >= 3.39.0)
45
45
  aws-sigv4 (~> 1.0)
46
- aws-sdk-ecs (1.22.0)
47
- aws-sdk-core (~> 3, >= 3.26.0)
46
+ aws-sdk-ecs (1.26.0)
47
+ aws-sdk-core (~> 3, >= 3.39.0)
48
48
  aws-sigv4 (~> 1.0)
49
- aws-sdk-elasticloadbalancingv2 (1.16.0)
50
- aws-sdk-core (~> 3, >= 3.26.0)
49
+ aws-sdk-elasticloadbalancingv2 (1.18.0)
50
+ aws-sdk-core (~> 3, >= 3.39.0)
51
51
  aws-sigv4 (~> 1.0)
52
52
  aws-sigv4 (1.0.3)
53
53
  byebug (10.0.2)
@@ -92,7 +92,7 @@ GEM
92
92
  text-table (1.2.4)
93
93
  thor (0.20.3)
94
94
  thread_safe (0.3.6)
95
- tilt (2.0.8)
95
+ tilt (2.0.9)
96
96
  tzinfo (1.2.5)
97
97
  thread_safe (~> 0.1)
98
98
 
@@ -109,4 +109,4 @@ DEPENDENCIES
109
109
  ufo!
110
110
 
111
111
  BUNDLED WITH
112
- 1.16.3
112
+ 1.17.1
@@ -18,11 +18,11 @@ Here's an example of creating web service with Fargate.
18
18
 
19
19
  git clone https://github.com/tongueroo/demo-ufo demo
20
20
  cd demo
21
- ufo init --image tongueroo/demo-ufo --launch-type fargate --execution-role-arn arn:aws:iam::123456789012:role/ecsTaskExecutionRole
21
+ ufo init --image tongueroo/demo-ufo --launch-type fargate --execution-role-arn arn:aws:iam::112233445566:role/ecsTaskExecutionRole
22
22
  ufo current --service demo-web
23
23
  ufo ship
24
24
 
25
- Replace the `--execution-role-arn` with the ecsTaskExecutionRole associated with your account. If you do not have an ecsTaskExecutionRole yet, create one by following [Amazon ECS Task Execution IAM Role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html) guide.
25
+ **IMPORTANT**: Replace the `--execution-role-arn` with the ecsTaskExecutionRole associated with your account. If you do not have an ecsTaskExecutionRole yet, create one by following [Amazon ECS Task Execution IAM Role](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html) guide.
26
26
 
27
27
  You should see output similiar to this. Some output has been removed for conciseness.
28
28
 
@@ -34,6 +34,9 @@ The `--task-only` option is useful. By default, the `ufo task` command will buil
34
34
 
35
35
  ```
36
36
  [--task-only], [--no-task-only] # Skip docker and task register steps. Only run the task.
37
+ w, [--wait], [--no-wait] # Wait for task to finish.
38
+ t, [--timeout=N] # How long to wait for task to finish.
39
+ # Default: 600
37
40
  c, [--command=one two three] # Override the command used for the container
38
41
  [--verbose], [--no-verbose]
39
42
  [--mute], [--no-mute]
@@ -2,7 +2,7 @@
2
2
  title: Quick Start
3
3
  ---
4
4
 
5
- In a hurry? No sweat! Here's a quick start to using ufo that takes only a few minutes. For this example, we will use a sinatra app from [tongueroo/demo-ufo](https://github.com/tongueroo/demo-ufo). The `ufo init` command sets up the ufo directory structure in your project. The `ufo ship` command deploys your code to an AWS ECS service. The `ufo ps` and `ufo scale` command shows you how to verify and scale additional containers.
5
+ In a hurry? No sweat! Here's a quick start to using ufo that takes only a few minutes. For this example, we will use a Sinatra app from [tongueroo/demo-ufo](https://github.com/tongueroo/demo-ufo). The `ufo init` command sets up the ufo directory structure in your project. The `ufo ship` command deploys your code to an AWS ECS service. The `ufo ps` and `ufo scale` command shows you how to verify and scale additional containers.
6
6
 
7
7
  gem install ufo
8
8
  git clone https://github.com/tongueroo/demo-ufo.git demo
@@ -13,15 +13,7 @@ In a hurry? No sweat! Here's a quick start to using ufo that takes only a few mi
13
13
  ufo ps
14
14
  ufo scale 2
15
15
 
16
- Note: The example pushes the Docker image to Dockerhub account. You need push access the repo. So, you will need to an account that you have access to. You can control that with the `--image` option. Example:
17
-
18
- ufo init --image=yourusername/yourrepo # use your own account
19
-
20
- Also, if you are using ECR instead, you can specific an ECR repo with the `--image` option. Example:
21
-
22
- ufo init --image 123456789012.dkr.ecr.us-west-2.amazonaws.com/myimage
23
-
24
- For more info, refer to the [ufo init](http://ufoships.com/reference/ufo-init/) reference docs.
16
+ Note: These quick start commands assume that you have push access to the repo. Refer to the Notes "Repo Push Access" section below for more info. It also assumes that you'd like to use ECS EC2 and assume that you have an ECS cluster with some EC2 Container instances running. Refer to the Notes "ECS EC2 vs ECS Fargate" section below for more info.
25
17
 
26
18
  ## What Happened
27
19
 
@@ -67,6 +59,28 @@ Congratulations! You have successfully deployed code to AWS ECS with ufo. It was
67
59
 
68
60
  Note: This quick start requires a working Docker installation. For Docker installation instructions refer to to the [Docker installation guide](https://docs.docker.com/engine/installation/).
69
61
 
62
+ ## Notes
63
+
64
+ ### Repo Push Access
65
+
66
+ The quick start example pushes the Docker image to a Dockerhub repo. You need your own repo with push access. This repo could be your own Dockerhub account or ECR repo. You can control the setting with the `--image` option. Example:
67
+
68
+ ufo init --image=yourusername/yourrepo # use your own account
69
+
70
+ Also, if you are using ECR instead, you can specify an ECR repo with the `--image` option. Example:
71
+
72
+ ufo init --image 123456789012.dkr.ecr.us-west-2.amazonaws.com/myimage
73
+
74
+ For more info, refer to the [ufo init](http://ufoships.com/reference/ufo-init/) reference docs.
75
+
76
+ ### ECS EC2 vs ECS Fargate
77
+
78
+ Ufo does not create the EC2 servers themselves to run the ECS tasks. If you use `ufo ship` to deploy an application to ECS EC2 and have not set up the EC2 servers, then the CloudFormation update will not be able to provision the ECS tasks and eventually roll back. Essentially it cannot create the ECS tasks because there are no EC2 servers to run them.
79
+
80
+ Refer to the AWS [Creating a Cluster](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create_cluster.html) docs to create an ECS cluster. Also refer to [ECS Terms Tutorial](https://blog.boltops.com/2017/09/08/aws-ecs-terms-tutorial) for an explanation of ECS terms.
81
+
82
+ If you would like not to manage the EC2 server fleet, you are looking for ECS Fargate instead of ECS EC2. ECS Fargate allows you to run ECS Tasks and AWS will manage the EC2 server fleet for you. Refer to the [Ufo Fargate]({% link _docs/fargate.md %}) docs and use those quick start like commands instead. The pricing for Fargate is more because AWS manages the server fleet for you. Refer to [Heroku vs ECS Fargate vs EC2 On-Demand vs EC2 Spot Pricing Comparison](https://blog.boltops.com/2018/04/22/heroku-vs-ecs-fargate-vs-ec2-on-demand-vs-ec2-spot-pricing-comparison) for a pricing comparison.
83
+
70
84
  Learn more in the next sections.
71
85
 
72
86
  <a id="next" class="btn btn-primary" href="{% link _docs/install.md %}">Next Step</a>
@@ -105,6 +105,8 @@ module Ufo
105
105
  desc "task TASK_DEFINITION", "Run a one-time task."
106
106
  long_desc Help.text(:task)
107
107
  option :task_only, type: :boolean, desc: "Skip docker and task register steps. Only run the task."
108
+ option :wait, type: :boolean, aliases: 'w', desc: "Wait for task to finish.", default: false
109
+ option :timeout, type: :numeric, aliases: 't', desc: "How long to wait for task to finish.", default: 600
108
110
  option :command, type: :array, aliases: 'c', desc: "Override the command used for the container"
109
111
  def task(task_definition)
110
112
  Docker::Builder.build(options) unless @options[:task_only]
@@ -26,7 +26,7 @@ module Ufo
26
26
  if @options[:command]
27
27
  task_options.merge!(overrides: overrides)
28
28
  puts "Running task with container overrides."
29
- puts "Command: #{@options[:command].join(' ')}"
29
+ puts "Command: #{command_in_human_readable_form}"
30
30
  end
31
31
 
32
32
  unless @options[:mute]
@@ -34,6 +34,8 @@ module Ufo
34
34
  display_params(task_options)
35
35
  end
36
36
 
37
+ ensure_log_group_exist
38
+
37
39
  resp = run_task(task_options)
38
40
  exit_if_failures!(resp)
39
41
  unless @options[:mute]
@@ -44,6 +46,10 @@ module Ufo
44
46
  end
45
47
  end
46
48
 
49
+ def ensure_log_group_exist
50
+ LogGroup.new(@task_definition, @options).create
51
+ end
52
+
47
53
  # Pretty hard to produce this edge case. Happens when:
48
54
  # launch_type: EC2
49
55
  # network_mode: awsvpc
@@ -66,7 +72,13 @@ module Ufo
66
72
  def run_task(options)
67
73
  puts "Equivalent aws cli command:"
68
74
  puts " aws ecs run-task --cluster #{@cluster} --task-definition #{options[:task_definition]}".colorize(:green)
69
- ecs.run_task(options)
75
+ run_task_result = ecs.run_task(options)
76
+ if @options[:wait]
77
+ task_arn = run_task_result.tasks[0].task_arn
78
+ raise SystemExit, exit_status_of_task(task_arn)
79
+ else
80
+ run_task_result
81
+ end
70
82
  rescue Aws::ECS::Errors::ClientException => e
71
83
  if e.message =~ /ECS was unable to assume the role/
72
84
  puts "ERROR: #{e.class} #{e.message}".colorize(:red)
@@ -172,7 +184,7 @@ module Ufo
172
184
  arns = task_definition_arns(@task_definition)
173
185
  # "arn:aws:ecs:us-east-1:<aws_account_id>:task-definition/wordpress:6",
174
186
  last_definition_arn = arns.first
175
- puts "last_definition_arn #{last_definition_arn}"
187
+ # puts "last_definition_arn #{last_definition_arn}"
176
188
  task_name = last_definition_arn.split("/").last
177
189
  resp = ecs.describe_task_definition(task_definition: task_name)
178
190
 
@@ -184,5 +196,28 @@ module Ufo
184
196
  def container_definition
185
197
  recent_task_definition.container_definitions[0].to_h
186
198
  end
199
+
200
+ def exit_status_of_task(task_arn)
201
+ waiter_max_attempts = @options[:timeout] / 5
202
+ waiter_delay = 5 # seconds long polling.
203
+
204
+ print "Waiting for task to complete."
205
+ ecs.wait_until(:tasks_stopped, { cluster: @cluster, tasks: [task_arn] }) do |waiter|
206
+ waiter.before_wait { print '.' }
207
+ waiter.delay = waiter_delay
208
+ waiter.max_attempts = waiter_max_attempts
209
+ end
210
+ puts
211
+ container = ecs.describe_tasks(cluster: @cluster, tasks: [task_arn]).tasks[0].containers[0]
212
+
213
+ container.exit_code.nil? ? 1 : container.exit_code
214
+ rescue Aws::Waiters::Errors::WaiterFailed
215
+ puts "It took longer than #{options[:timeout]} seconds to run #{command_in_human_readable_form} (#{task_arn})"
216
+ exit 1
217
+ end
218
+
219
+ def command_in_human_readable_form
220
+ @options[:command].join(' ')
221
+ end
187
222
  end
188
223
  end
@@ -1,3 +1,3 @@
1
1
  module Ufo
2
- VERSION = "4.1.7"
2
+ VERSION = "4.1.8"
3
3
  end
@@ -1,4 +1,4 @@
1
- describe Ufo::Ship do
1
+ describe Ufo::Task do
2
2
  before(:each) do
3
3
  create_ufo_project
4
4
  end
@@ -8,11 +8,6 @@ describe Ufo::Ship do
8
8
  }
9
9
  end
10
10
  let(:task_definition) { "hi-migrate-prod" }
11
- let(:task) do
12
- task = Ufo::Task.new(task_definition, options)
13
- allow(task).to receive(:ecs).and_return(ecs_client)
14
- task
15
- end
16
11
 
17
12
  context "hi-migrate-prod" do
18
13
  it "should migrate the database" do
@@ -20,15 +15,39 @@ describe Ufo::Ship do
20
15
 
21
16
  expect(task.ecs).to have_received(:run_task)
22
17
  end
18
+
19
+ it "should wait for the command to finish" do
20
+ expect do
21
+ task(wait: true, timeout: 600).run
22
+ expect(task.ecs).to have_received(:run_task)
23
+ end.to raise_error(SystemExit) do |error|
24
+ expect(error.status).to eq(5)
25
+ end
26
+ end
23
27
  end
24
28
 
25
29
  # mocks
26
30
  def ecs_client
27
31
  ecs = double("ecs")
32
+ ecs_container = double("ecs_container")
28
33
  fake_response = double('fake-response').as_null_object
29
34
  allow(ecs).to receive(:run_task).and_return(fake_response)
35
+ allow(ecs).to receive(:wait_until).and_return(fake_response)
36
+ allow(ecs).to receive(:describe_tasks).and_return(OpenStruct.new({
37
+ tasks: [OpenStruct.new(containers: [ecs_container])]
38
+ }))
30
39
  allow(ecs).to receive(:list_task_definitions).and_return(fake_response)
31
40
  allow(ecs).to receive(:describe_task_definition).and_return(fake_response)
41
+ allow(ecs_container).to receive(:exit_code).and_return(5)
32
42
  ecs
33
43
  end
44
+
45
+ def task option_overwrites = {}
46
+ @task ||=
47
+ begin
48
+ result = Ufo::Task.new(task_definition, options.merge(option_overwrites))
49
+ allow(result).to receive(:ecs).and_return(ecs_client)
50
+ result
51
+ end
52
+ end
34
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ufo
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.7
4
+ version: 4.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-13 00:00:00.000000000 Z
11
+ date: 2018-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-cloudformation