ufo 3.5.7 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/Gemfile.lock +16 -10
  4. data/README.md +12 -13
  5. data/docs/_config.yml +1 -1
  6. data/docs/_docs/auto-completion.md +4 -4
  7. data/docs/_docs/automated-cleanup.md +1 -1
  8. data/docs/_docs/conventions.md +7 -7
  9. data/docs/_docs/customize-cloudformation.md +36 -0
  10. data/docs/_docs/faq.md +9 -7
  11. data/docs/_docs/fargate.md +102 -0
  12. data/docs/_docs/helpers.md +3 -3
  13. data/docs/_docs/load-balancer.md +72 -0
  14. data/docs/_docs/migrations.md +2 -2
  15. data/docs/_docs/next-steps.md +2 -2
  16. data/docs/_docs/params.md +12 -41
  17. data/docs/_docs/route53-support.md +28 -0
  18. data/docs/_docs/run-in-pieces.md +2 -2
  19. data/docs/_docs/security-groups.md +54 -0
  20. data/docs/_docs/settings-cfn.md +11 -0
  21. data/docs/_docs/settings-network.md +34 -0
  22. data/docs/_docs/settings.md +18 -15
  23. data/docs/_docs/single-task.md +3 -3
  24. data/docs/_docs/ssl-support.md +42 -0
  25. data/docs/_docs/structure.md +5 -1
  26. data/docs/_docs/stuck-cloudformation.md +30 -0
  27. data/docs/_docs/tutorial-ufo-docker-build.md +19 -31
  28. data/docs/_docs/tutorial-ufo-init.md +16 -12
  29. data/docs/_docs/tutorial-ufo-ship.md +50 -54
  30. data/docs/_docs/tutorial-ufo-ships.md +9 -7
  31. data/docs/_docs/tutorial-ufo-tasks-build.md +26 -17
  32. data/docs/_docs/ufo-current.md +50 -0
  33. data/docs/_docs/ufo-env-extra.md +21 -0
  34. data/docs/_docs/ufo-env.md +6 -13
  35. data/docs/_docs/ufo-tasks-register.md +3 -3
  36. data/docs/_docs/upgrade4.md +49 -0
  37. data/docs/_docs/variables.md +5 -5
  38. data/docs/_docs/why-cloudformation.md +22 -0
  39. data/docs/_includes/about.html +1 -1
  40. data/docs/_includes/cfn-customize.md +39 -0
  41. data/docs/_includes/commands.html +6 -6
  42. data/docs/_includes/css/ufo.css +1 -0
  43. data/docs/_includes/example.html +13 -13
  44. data/docs/_includes/reference.md +1 -1
  45. data/docs/_includes/subnav.html +22 -5
  46. data/docs/_includes/ufo-ship-options.md +7 -6
  47. data/docs/_reference/ufo-apps.md +36 -0
  48. data/docs/_reference/ufo-cancel.md +24 -0
  49. data/docs/_reference/ufo-completion.md +1 -1
  50. data/docs/_reference/ufo-completion_script.md +1 -1
  51. data/docs/_reference/ufo-current.md +93 -0
  52. data/docs/_reference/ufo-deploy.md +18 -17
  53. data/docs/_reference/ufo-destroy.md +6 -4
  54. data/docs/_reference/ufo-docker-base.md +7 -7
  55. data/docs/_reference/ufo-docker-build.md +9 -9
  56. data/docs/_reference/ufo-docker-clean.md +8 -8
  57. data/docs/_reference/ufo-docker-name.md +4 -4
  58. data/docs/_reference/ufo-docker.md +4 -2
  59. data/docs/_reference/ufo-init.md +31 -20
  60. data/docs/_reference/ufo-network-help.md +15 -0
  61. data/docs/_reference/ufo-network-init.md +38 -0
  62. data/docs/_reference/ufo-network.md +26 -0
  63. data/docs/_reference/ufo-ps.md +53 -0
  64. data/docs/_reference/ufo-releases.md +40 -0
  65. data/docs/_reference/ufo-resources.md +44 -0
  66. data/docs/_reference/ufo-rollback.md +59 -0
  67. data/docs/_reference/ufo-scale.md +23 -3
  68. data/docs/_reference/ufo-ship.md +54 -27
  69. data/docs/_reference/ufo-ships.md +17 -26
  70. data/docs/_reference/ufo-stop.md +31 -0
  71. data/docs/_reference/ufo-task.md +15 -16
  72. data/docs/_reference/ufo-tasks-build.md +10 -10
  73. data/docs/_reference/ufo-tasks-register.md +3 -3
  74. data/docs/_reference/ufo-tasks.md +1 -1
  75. data/docs/_reference/ufo-upgrade-help.md +15 -0
  76. data/docs/_reference/ufo-upgrade-v2to3.md +15 -0
  77. data/docs/_reference/ufo-upgrade-v3_3to3_4.md +15 -0
  78. data/docs/_reference/ufo-upgrade-v3to4.md +27 -0
  79. data/docs/_reference/ufo-upgrade.md +28 -0
  80. data/docs/_reference/ufo-version.md +1 -1
  81. data/docs/articles.md +2 -2
  82. data/docs/docs.md +1 -1
  83. data/docs/img/docs/cloudformation-resources.png +0 -0
  84. data/docs/img/tutorials/ecs-console-task-definitions.png +0 -0
  85. data/docs/img/tutorials/ecs-console-ufo-ship.png +0 -0
  86. data/docs/img/tutorials/ecs-console-ufo-ships.png +0 -0
  87. data/docs/quick-start.md +21 -9
  88. data/docs/reference.md +10 -2
  89. data/exe/ufo +1 -1
  90. data/lib/cfn/stack.yml +259 -0
  91. data/lib/template/.ufo/params.yml.tt +21 -60
  92. data/lib/template/.ufo/settings.yml.tt +6 -1
  93. data/lib/template/.ufo/settings/cfn/default.yml.tt +55 -0
  94. data/lib/template/.ufo/settings/network/default.yml.tt +18 -0
  95. data/lib/template/.ufo/task_definitions.rb.tt +7 -6
  96. data/lib/template/.ufo/templates/fargate.json.erb +1 -1
  97. data/lib/template/.ufo/templates/main.json.erb +1 -0
  98. data/lib/template/.ufo/variables/base.rb.tt +5 -2
  99. data/lib/template/Dockerfile +10 -15
  100. data/lib/template/bin/deploy.tt +2 -2
  101. data/lib/ufo.rb +29 -20
  102. data/lib/ufo/apps.rb +49 -0
  103. data/lib/ufo/apps/cfn_map.rb +70 -0
  104. data/lib/ufo/apps/service.rb +56 -0
  105. data/lib/ufo/aws_service.rb +15 -6
  106. data/lib/ufo/base.rb +32 -0
  107. data/lib/ufo/cancel.rb +23 -0
  108. data/lib/ufo/cli.rb +91 -27
  109. data/lib/ufo/core.rb +35 -3
  110. data/lib/ufo/current.rb +104 -0
  111. data/lib/ufo/destroy.rb +10 -41
  112. data/lib/ufo/docker/builder.rb +5 -4
  113. data/lib/ufo/docker/cleaner.rb +1 -1
  114. data/lib/ufo/docker/pusher.rb +2 -2
  115. data/lib/ufo/ecr/cleaner.rb +1 -1
  116. data/lib/ufo/help/apps.md +12 -0
  117. data/lib/ufo/help/balancer.md +3 -0
  118. data/lib/ufo/help/current.md +65 -0
  119. data/lib/ufo/help/deploy.md +4 -4
  120. data/lib/ufo/help/destroy.md +3 -3
  121. data/lib/ufo/help/docker.md +3 -1
  122. data/lib/ufo/help/docker/base.md +7 -7
  123. data/lib/ufo/help/docker/build.md +9 -9
  124. data/lib/ufo/help/docker/clean.md +8 -8
  125. data/lib/ufo/help/docker/name.md +4 -4
  126. data/lib/ufo/help/help.md +5 -0
  127. data/lib/ufo/help/init.md +24 -16
  128. data/lib/ufo/help/network/init.md +13 -0
  129. data/lib/ufo/help/ps.md +27 -0
  130. data/lib/ufo/help/releases.md +16 -0
  131. data/lib/ufo/help/resources.md +20 -0
  132. data/lib/ufo/help/rollback.md +35 -0
  133. data/lib/ufo/help/scale.md +22 -2
  134. data/lib/ufo/help/ship.md +40 -14
  135. data/lib/ufo/help/ships.md +4 -13
  136. data/lib/ufo/help/stop.md +7 -0
  137. data/lib/ufo/help/task.md +9 -9
  138. data/lib/ufo/help/tasks/build.md +10 -10
  139. data/lib/ufo/help/tasks/register.md +3 -3
  140. data/lib/ufo/help/upgrade/v3to4.md +3 -0
  141. data/lib/ufo/info.rb +62 -0
  142. data/lib/ufo/init.rb +36 -23
  143. data/lib/ufo/log_group.rb +2 -1
  144. data/lib/ufo/network.rb +24 -0
  145. data/lib/ufo/network/fetch.rb +41 -0
  146. data/lib/ufo/network/helper.rb +23 -0
  147. data/lib/ufo/network/init.rb +26 -0
  148. data/lib/ufo/param.rb +5 -5
  149. data/lib/ufo/ps.rb +102 -0
  150. data/lib/ufo/ps/task.rb +78 -0
  151. data/lib/ufo/releases.rb +14 -0
  152. data/lib/ufo/rollback.rb +53 -0
  153. data/lib/ufo/scale.rb +6 -12
  154. data/lib/ufo/sequence.rb +7 -0
  155. data/lib/ufo/setting.rb +7 -6
  156. data/lib/ufo/setting/profile.rb +24 -0
  157. data/lib/ufo/ship.rb +35 -326
  158. data/lib/ufo/stack.rb +203 -0
  159. data/lib/ufo/stack/context.rb +242 -0
  160. data/lib/ufo/stack/helper.rb +28 -0
  161. data/lib/ufo/stack/status.rb +195 -0
  162. data/lib/ufo/stop.rb +47 -0
  163. data/lib/ufo/task.rb +96 -15
  164. data/lib/ufo/tasks/register.rb +1 -1
  165. data/lib/ufo/template_scope.rb +81 -7
  166. data/lib/ufo/upgrade.rb +32 -0
  167. data/lib/ufo/{upgrade3.rb → upgrade/upgrade3.rb} +1 -1
  168. data/lib/ufo/{upgrade33_to_34.rb → upgrade/upgrade33to34.rb} +2 -2
  169. data/lib/ufo/upgrade/upgrade4.rb +161 -0
  170. data/lib/ufo/util.rb +19 -6
  171. data/lib/ufo/version.rb +1 -1
  172. data/spec/fixtures/apps/describe_services.json +96 -0
  173. data/spec/fixtures/cfn/stack-events-complete.json +1080 -0
  174. data/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
  175. data/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
  176. data/spec/fixtures/deployments.json +50 -0
  177. data/spec/fixtures/ps/describe_tasks.json +58 -0
  178. data/spec/fixtures/settings.yml +2 -0
  179. data/spec/lib/apps_spec.rb +20 -0
  180. data/spec/lib/cli_spec.rb +4 -4
  181. data/spec/lib/ps_spec.rb +14 -0
  182. data/spec/lib/setting_spec.rb +2 -1
  183. data/spec/lib/ship_spec.rb +6 -30
  184. data/spec/lib/stack/status_spec.rb +76 -0
  185. data/spec/lib/stop_spec.rb +13 -0
  186. data/spec/lib/task_spec.rb +5 -2
  187. data/spec/spec_helper.rb +1 -1
  188. data/ufo.gemspec +2 -0
  189. metadata +120 -6
  190. data/docs/_reference/ufo-upgrade3.md +0 -23
  191. data/docs/_reference/ufo-upgrade3_3_to_3_4.md +0 -23
@@ -1,23 +1,23 @@
1
1
  module Ufo
2
2
  class Init < Sequence
3
- add_runtime_options! # force, pretend, quiet, skip options
4
- # https://github.com/erikhuda/thor/blob/master/lib/thor/actions.rb#L49
3
+ include Network::Helper
5
4
 
6
5
  # Ugly, this is how I can get the options from to match with this Thor::Group
7
6
  def self.cli_options
8
7
  [
9
8
  [:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
10
- [:image, required: true, desc: "Docker image name without the tag. Example: tongueroo/hi. Configures ufo/settings.yml"],
11
- [:app, required: true, desc: "App name. Preferably one word. Used in the generated ufo/task_definitions.rb."],
9
+ [:image, required: true, desc: "Docker image name without the tag. Example: tongueroo/demo-ufo. Configures ufo/settings.yml"],
10
+ [:app, desc: "App name. Preferably one word. Used in the generated ufo/task_definitions.rb. If not specified then the app name is inferred as the folder name."],
12
11
  [:launch_type, default: "ec2", desc: "ec2 or fargate."],
13
12
  [:execution_role_arn, desc: "execution role arn used by tasks, required for fargate."],
14
13
  [:template, desc: "Custom template to use."],
15
14
  [:template_mode, desc: "Template mode: replace or additive."],
15
+ [:vpc_id, desc: "Vpc id. For settings/network/default.yml."],
16
+ [:ecs_subnets, type: :array, desc: "Subnets for ECS tasks, defaults to --elb-subnets set to. For settings/network/default.yml"],
17
+ [:elb_subnets, type: :array, desc: "Subnets for ELB. For settings/network/default.yml"],
16
18
  ]
17
19
  end
18
- cli_options.each do |args|
19
- class_option *args
20
- end
20
+ cli_options.each { |o| class_option(*o) }
21
21
 
22
22
  def setup_template_repo
23
23
  return unless @options[:template]&.include?('/')
@@ -48,26 +48,29 @@ module Ufo
48
48
  FileUtils.cd(dest)
49
49
  end
50
50
 
51
+ def set_network_options
52
+ configure_network_settings
53
+ end
54
+
51
55
  def init_files
52
56
  # map variables
53
- @app = options[:app]
57
+ @app = options[:app] || inferred_app
54
58
  @image = options[:image]
55
59
  @execution_role_arn_input = get_execution_role_arn_input
56
60
  # copy the files
57
61
  puts "Setting up ufo project..."
58
- directory ".", exclude_pattern: /(\.git|templates)/
59
-
60
- if @options[:launch_type] == "fargate"
61
- copy_file ".ufo/templates/fargate.json.erb", ".ufo/templates/main.json.erb"
62
- else
63
- copy_file ".ufo/templates/main.json.erb"
64
- end
62
+ exclude_pattern = File.exist?("#{Ufo.root}/Dockerfile") ?
63
+ /(\.git|Dockerfile)/ :
64
+ /(\.git)/
65
+ directory ".", exclude_pattern: exclude_pattern
65
66
  end
66
67
 
67
68
  def upsert_gitignore
68
69
  text =<<-EOL
69
- .ufo/output
70
+ .ufo/current
70
71
  .ufo/data
72
+ .ufo/log
73
+ .ufo/output
71
74
  EOL
72
75
  if File.exist?(".gitignore")
73
76
  append_to_file ".gitignore", text
@@ -77,9 +80,7 @@ EOL
77
80
  end
78
81
 
79
82
  def upsert_dockerignore
80
- text =<<-EOL
81
- .ufo
82
- EOL
83
+ text = ".ufo\n"
83
84
  if File.exist?(".dockerignore")
84
85
  append_to_file ".dockerignore", text
85
86
  else
@@ -90,18 +91,30 @@ EOL
90
91
  def user_message
91
92
  puts "Starter ufo files created."
92
93
  puts <<-EOL
94
+ Congrats 🎉 You have successfully set up ufo for your project.
93
95
  #{"="*64}
94
- Congrats 🎉 You have successfully set up ufo for your project. To deploy to ECS:
95
96
 
96
- ufo ship #{@app}-web
97
+ ## Task Definition Customizations
97
98
 
98
99
  If you need to customize the ECS task definition to configure things like memory and cpu allocation. You can do this by adjusting the files the .ufo/variables folder. These variables get applied to the .ufo/templates/main.json.erb task definition json that is passed to the ECS register task definition api.
99
100
 
100
101
  Some additional starter example roles for your apps were set up in in .ufo/task_definitions.rb. Be sure to check it out and adjust it for your needs.
101
102
 
102
- This allows you to fully customize and control your environment to fit your application's needs.
103
+ ## Settings files
104
+
105
+ Additionally, ufo generated starter settings files at that further allow you to customize more settings.
106
+
107
+ * .ufo/settings.yml: general settings.
108
+ * .ufo/settings/cfn/default.yml: properties of CloudFormation resources that ufo creates.
109
+ * .ufo/settings/network/default.yml: network settings.
110
+
111
+ More more info refer to: http://ufoships.com/docs/settings/
112
+
113
+ To deploy to ECS:
114
+
115
+ ufo current --service #{@app}-web
116
+ ufo ship
103
117
 
104
- More info: http://ufoships.com
105
118
  EOL
106
119
  end
107
120
  end
@@ -9,7 +9,7 @@ module Ufo
9
9
  end
10
10
 
11
11
  def create
12
- puts "Ensuring log group for #{@task_definition} exists"
12
+ puts "Ensuring log group for #{@task_definition.colorize(:green)} task definition exists"
13
13
  return if @options[:noop]
14
14
 
15
15
  Ufo.check_task_definition!(@task_definition)
@@ -17,6 +17,7 @@ module Ufo
17
17
  task_def["containerDefinitions"].each do |container_def|
18
18
  begin
19
19
  log_group_name = container_def["logConfiguration"]["options"]["awslogs-group"]
20
+ puts "Log group name: #{log_group_name}"
20
21
  rescue NoMethodError
21
22
  # silence when the logConfiguration is not specified
22
23
  end
@@ -0,0 +1,24 @@
1
+ module Ufo
2
+ class Network < Command
3
+ autoload :Init, "ufo/network/init"
4
+ autoload :Helper, "ufo/network/helper"
5
+ autoload :Fetch, "ufo/network/fetch"
6
+
7
+ def self.cli_options
8
+ [
9
+ [:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
10
+ [:subnets, type: :array, desc: "Subnets"],
11
+ [:vpc_id, desc: "Vpc id"],
12
+ [:filename, default: "default", desc: "Name of the settings file to create w/o extension."],
13
+ ]
14
+ end
15
+
16
+ cli_options.each { |o| option(*o) }
17
+
18
+ desc "init", "Creates network starter settings file."
19
+ long_desc Help.text("network:init")
20
+ def init
21
+ Init.start
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ # Provides access to default network settings for a vpc: subnets and security_group
2
+ # If no @vpc_id is provided to the initializer then the default vpc is used.
3
+ class Ufo::Network
4
+ class Fetch
5
+ include Ufo::AwsService
6
+ extend Memoist
7
+
8
+ def initialize(vpc_id)
9
+ @vpc_id = vpc_id
10
+ end
11
+
12
+ def vpc_id
13
+ return @vpc_id if @vpc_id
14
+
15
+ resp = ec2.describe_vpcs(filters: [
16
+ {name: "isDefault", values: ["true"]}
17
+ ])
18
+ resp.vpcs.first.vpc_id
19
+ end
20
+ memoize :vpc_id
21
+
22
+ # all subnets
23
+ def subnet_ids
24
+ resp = ec2.describe_subnets(filters: [
25
+ {name: "vpc-id", values: [vpc_id]}
26
+ ])
27
+ resp.subnets.map(&:subnet_id).sort
28
+ end
29
+ memoize :subnet_ids
30
+
31
+ # default security group
32
+ def security_group_id
33
+ resp = ec2.describe_security_groups(filters: [
34
+ {name: "vpc-id", values: [vpc_id]},
35
+ {name: "group-name", values: ["default"]}
36
+ ])
37
+ resp.security_groups.first.group_id
38
+ end
39
+ memoize :security_group_id
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ class Ufo::Network
2
+ module Helper
3
+ private
4
+ # for balancer default profile
5
+ def configure_network_settings
6
+ @options = @options.dup
7
+ return test_network_settings if ENV['TEST']
8
+
9
+ fetch = Fetch.new(@options[:vpc_id])
10
+ @options[:vpc_id] ||= fetch.vpc_id
11
+ @options[:ecs_subnets] ||= fetch.subnet_ids
12
+ @options[:elb_subnets] ||= fetch.subnet_ids
13
+ end
14
+
15
+ # hack for specs
16
+ def test_network_settings
17
+ @options[:vpc_id] = "vpc-111"
18
+ @options[:ecs_subnets] = ["subnet-111", "subnet-222"]
19
+ @options[:elb_subnets] = ["subnet-111", "subnet-222"]
20
+ @options
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ module Ufo
2
+ class Network::Init < Thor::Group
3
+ include Thor::Actions
4
+ include Network::Helper
5
+
6
+ add_runtime_options! # force, pretend, quiet, skip options
7
+ # https://github.com/erikhuda/thor/blob/master/lib/thor/actions.rb#L49
8
+
9
+ # Interesting, when defining the options in this class it screws up the ufo balance -h menu
10
+ Network.cli_options.each do |o|
11
+ class_option *o
12
+ end
13
+ def self.source_paths
14
+ [File.expand_path("../../../template/.ufo/settings/network", __FILE__)]
15
+ end
16
+
17
+ def set_network_options
18
+ configure_network_settings
19
+ end
20
+
21
+ def starter_files
22
+ filename = @options[:filename] || "default"
23
+ template "default.yml", ".ufo/settings/network/#{filename}.yml"
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,4 @@
1
1
  require 'yaml'
2
- require 'memoist'
3
2
 
4
3
  module Ufo
5
4
  class Param
@@ -13,7 +12,8 @@ module Ufo
13
12
  upgrade_message!
14
13
 
15
14
  result = RenderMePretty.result(@params_path, context: template_scope)
16
- YAML.load(result)
15
+ data = YAML.load(result) || {}
16
+ data.deep_symbolize_keys
17
17
  end
18
18
  memoize :data
19
19
 
@@ -24,15 +24,15 @@ module Ufo
24
24
  # Ufo version 3.3 to 3.4 added a concept of a .ufo/params.yml file to support
25
25
  # fargate: https://github.com/tongueroo/ufo/pull/31
26
26
  #
27
- # Warn user and tell them to run the `ufo upgrade3_3_to_3_4` command to upgrade.
27
+ # Warn user and tell them to run the `ufo upgrade v3_3to3_4` command to upgrade.
28
28
  def upgrade_message!
29
29
  return if File.exist?(@params_path)
30
30
 
31
31
  puts "ERROR: Your project is missing the .ufo/params.yml.".colorize(:red)
32
- puts "This was added in ufo version 3.4 for Fargate support: https://github.com/tongueroo/ufo/pull/31"
32
+ puts "This was added in ufo version 3.4"
33
33
  puts "You can find more info about the params file here: http://ufoships.com/docs/params/"
34
34
  puts "To upgrade run:"
35
- puts " ufo upgrade3_3_to_3_4"
35
+ puts " ufo upgrade v3_3to3_4"
36
36
  exit 1
37
37
  end
38
38
  end
@@ -0,0 +1,102 @@
1
+ require 'text-table'
2
+
3
+ module Ufo
4
+ class Ps < Base
5
+ autoload :Task, 'ufo/ps/task'
6
+
7
+ delegate :service, to: :info
8
+
9
+ def run
10
+ unless service
11
+ puts no_service_message
12
+ return
13
+ end
14
+
15
+ summary
16
+ if task_arns.empty?
17
+ puts "There are 0 running tasks."
18
+ return
19
+ end
20
+
21
+ resp = ecs.describe_tasks(tasks: task_arns, cluster: @cluster)
22
+ display_info(resp)
23
+
24
+ display_scale_help
25
+ display_target_group_help
26
+ end
27
+
28
+ def summary
29
+ return unless @options[:summary]
30
+ puts "=> Service: #{@pretty_service_name}"
31
+ puts " Service name: #{service.service_name}"
32
+ puts " Status: #{service.status}"
33
+ puts " Running count: #{service.running_count}"
34
+ puts " Desired count: #{service.desired_count}"
35
+ puts " Launch type: #{service.launch_type}"
36
+ puts " Task definition: #{service.task_definition.split('/').last}"
37
+ elb = info.load_balancer(service)
38
+ if elb
39
+ puts " Elb: #{elb.dns_name}"
40
+ puts " Elb type: #{elb.type}"
41
+ end
42
+ puts " Route53: #{info.route53_dns}" if info.route53_dns
43
+ end
44
+
45
+ def display_target_group_help
46
+ events = service["events"][0..4]
47
+ return if events[0].message =~ /has reached a steady state/
48
+
49
+ # The error currently happens to be the 5th element.
50
+ #
51
+ # Example:
52
+ # "(service XXX) (instance i-XXX) (port 32875) is unhealthy in (target-group arn:aws:elasticloadbalancing:us-east-1:111111111111:targetgroup/devel-Targe-1111111111111/1111111111111111) due to (reason Health checks failed with these codes: [400])">]
53
+ error_event = events.find do |e|
54
+ e.message =~ /is unhealthy in/ &&
55
+ e.message =~ /targetgroup/
56
+ end
57
+ return unless error_event
58
+
59
+ puts "There are targets the target group reporting unhealthy. This can cause containers to cycle. Here's the error:"
60
+ puts error_event.message.colorize(:red)
61
+ puts "Check out the ECS console events tab for more info."
62
+ end
63
+
64
+ # If the running count less than the desired account yet, check the events
65
+ # and show a message with helpful debugging information.
66
+ def display_scale_help
67
+ return if service.running_count >= service.desired_count
68
+
69
+ events = service["events"][0..3] # only check most recent 4 messages
70
+ error_event = events.find do |e|
71
+ e.message =~ /was unable to place a task/
72
+ end
73
+ return unless error_event
74
+
75
+ puts "There is an issue scaling the #{@service.colorize(:green)} service to #{service.desired_count}. Here's the error:"
76
+ puts error_event.message.colorize(:red)
77
+ end
78
+
79
+ def display_info(resp)
80
+ table = Text::Table.new
81
+ table.head = Task.header
82
+ resp["tasks"].each do |t|
83
+ task = Task.new(t)
84
+ table.rows << task.to_a unless task.hide?
85
+ end
86
+ puts table
87
+ end
88
+
89
+ def task_arns
90
+ threads, results = [], {}
91
+ statuses = %w[RUNNING PENDING STOPPED]
92
+ statuses.each do |status|
93
+ threads << Thread.new do
94
+ resp = ecs.list_tasks(service_name: service.service_name, cluster: @cluster, desired_status: status)
95
+ results[status] = resp.task_arns
96
+ end
97
+ end
98
+ threads.map(&:join)
99
+ results.values.flatten.uniq
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,78 @@
1
+ class Ufo::Ps
2
+ class Task
3
+ def self.header
4
+ %w[Id Name Release Started Status Notes]
5
+ end
6
+
7
+ def initialize(task)
8
+ @task = task
9
+ end
10
+
11
+ def to_a
12
+ [id, name, release, started, status, notes]
13
+ end
14
+
15
+ def id
16
+ @task['task_arn'].split('/').last.split('-').first
17
+ end
18
+
19
+ def name
20
+ @task["overrides"]["container_overrides"].first["name"]
21
+ rescue NoMethodError
22
+ @task["containers"].first["name"]
23
+ end
24
+
25
+ def release
26
+ @task["task_definition_arn"].split('/').last
27
+ end
28
+
29
+ def started
30
+ started = Time.parse(@task["started_at"].to_s)
31
+ relative_time(started)
32
+ rescue ArgumentError
33
+ "PENDING"
34
+ end
35
+
36
+ def started_at
37
+ Time.parse(@task["started_at"].to_s)
38
+ rescue ArgumentError
39
+ nil
40
+ end
41
+
42
+ # hide stopped tasks that are older than 10 minutes
43
+ def hide?
44
+ status == "STOPPED" && started_at < Time.now - 60 * 10
45
+ end
46
+
47
+ def status
48
+ @task["last_status"]
49
+ end
50
+
51
+ def notes
52
+ return unless @task["stopped_reason"]
53
+
54
+ if @task["stopped_reason"] =~ /Task failed ELB health checks/
55
+ "Failed ELB health check"
56
+ else
57
+ @task["stopped_reason"]
58
+ end
59
+ end
60
+
61
+ # https://stackoverflow.com/questions/195740/how-do-you-do-relative-time-in-rails/195894
62
+ def relative_time(start_time)
63
+ diff_seconds = Time.now - start_time
64
+ case diff_seconds
65
+ when 0 .. 59
66
+ "#{diff_seconds.to_i} seconds ago"
67
+ when 60 .. (3600-1)
68
+ "#{(diff_seconds/60).to_i} minutes ago"
69
+ when 3600 .. (3600*24-1)
70
+ "#{(diff_seconds/3600).to_i} hours ago"
71
+ when (3600*24) .. (3600*24*30)
72
+ "#{(diff_seconds/(3600*24)).to_i} days ago"
73
+ else
74
+ start_time.strftime("%m/%d/%Y")
75
+ end
76
+ end
77
+ end
78
+ end