ufo 3.3.2 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile.lock +9 -7
  4. data/docs/README.md +1 -2
  5. data/docs/_docs/params.md +72 -0
  6. data/docs/_docs/settings.md +1 -6
  7. data/docs/_docs/tutorial-ufo-init.md +0 -5
  8. data/docs/_docs/ufo-env.md +1 -1
  9. data/docs/_includes/subnav.html +1 -0
  10. data/docs/_reference/ufo-deploy.md +9 -1
  11. data/docs/_reference/ufo-init.md +30 -9
  12. data/docs/_reference/ufo-task.md +11 -12
  13. data/docs/_reference/ufo-upgrade3_3_to_3_4.md +23 -0
  14. data/docs/reference.md +1 -0
  15. data/lib/template/.ufo/params.yml.tt +65 -0
  16. data/lib/template/.ufo/settings.yml.tt +0 -4
  17. data/lib/template/.ufo/templates/fargate.json.erb +37 -0
  18. data/lib/template/.ufo/variables/base.rb.tt +15 -0
  19. data/lib/template/.ufo/variables/development.rb +1 -1
  20. data/lib/ufo.rb +3 -1
  21. data/lib/ufo/cli.rb +7 -3
  22. data/lib/ufo/default/settings.yml +0 -4
  23. data/lib/ufo/destroy.rb +1 -1
  24. data/lib/ufo/docker/builder.rb +1 -5
  25. data/lib/ufo/docker/cleaner.rb +1 -2
  26. data/lib/ufo/docker/pusher.rb +1 -5
  27. data/lib/ufo/dsl.rb +1 -1
  28. data/lib/ufo/dsl/helper.rb +3 -8
  29. data/lib/ufo/dsl/task_definition.rb +7 -45
  30. data/lib/ufo/ecr/cleaner.rb +2 -2
  31. data/lib/ufo/help/deploy.md +9 -1
  32. data/lib/ufo/help/init.md +18 -0
  33. data/lib/ufo/help/task.md +6 -6
  34. data/lib/ufo/init.rb +9 -2
  35. data/lib/ufo/param.rb +24 -0
  36. data/lib/ufo/scale.rb +1 -1
  37. data/lib/ufo/sequence.rb +14 -0
  38. data/lib/ufo/ship.rb +6 -6
  39. data/lib/ufo/task.rb +9 -1
  40. data/lib/ufo/tasks/register.rb +21 -1
  41. data/lib/ufo/template_scope.rb +45 -0
  42. data/lib/ufo/upgrade/params.yml +47 -0
  43. data/lib/ufo/upgrade33_to_34.rb +32 -0
  44. data/lib/ufo/util.rb +25 -0
  45. data/lib/ufo/version.rb +1 -1
  46. data/spec/fixtures/settings.yml +0 -4
  47. data/spec/lib/setting_spec.rb +3 -3
  48. data/spec/spec_helper.rb +1 -1
  49. data/ufo.gemspec +1 -0
  50. metadata +25 -4
  51. data/lib/template/.ufo/variables/base.rb +0 -6
  52. data/lib/ufo/default.rb +0 -40
@@ -0,0 +1,15 @@
1
+ # Example ufo/variables/base.rb
2
+ # More info on how variables work: http://ufoships.com/docs/variables/
3
+ @image = helper.full_image_name # includes the git sha tongueroo/hi:ufo-[sha].
4
+ @environment = helper.env_file(".env")
5
+ <% if @options[:launch_type] == "fargate" -%>
6
+ # Ensure that the cpu and memory values are a supported combination by Fargate.
7
+ # More info: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task-cpu-memory-error.html"
8
+ <% end -%>
9
+ @cpu = 256
10
+ @memory = 512
11
+ @memory_reservation = 256
12
+
13
+ <% if @execution_role_arn_input -%>
14
+ @execution_role_arn = "<%= @execution_role_arn_input %>"
15
+ <% end -%>
@@ -1,6 +1,6 @@
1
1
  # Example ufo/variables/development.rb
2
2
  # More info on how variables work: http://ufoships.com/docs/variables/
3
- @cpu = 192
3
+ @cpu = 256
4
4
  @environment = helper.env_vars(%Q[
5
5
  RAILS_ENV=development
6
6
  SECRET_KEY_BASE=secret
data/lib/ufo.rb CHANGED
@@ -7,7 +7,6 @@ require 'render_me_pretty'
7
7
 
8
8
  module Ufo
9
9
  autoload :Core, 'ufo/core'
10
- autoload :Default, 'ufo/default'
11
10
  autoload :AwsService, 'ufo/aws_service'
12
11
  autoload :Command, 'ufo/command'
13
12
  autoload :Setting, 'ufo/setting'
@@ -23,6 +22,8 @@ module Ufo
23
22
  autoload :Scale, 'ufo/scale'
24
23
  autoload :LogGroup, 'ufo/log_group'
25
24
  autoload :ECS, 'ufo/ecs'
25
+ autoload :Param, 'ufo/param'
26
+ autoload :TemplateScope, 'ufo/template_scope'
26
27
 
27
28
  autoload :Docker, 'ufo/docker'
28
29
  autoload :Ecr, 'ufo/ecr'
@@ -30,6 +31,7 @@ module Ufo
30
31
  autoload :Completion, "ufo/completion"
31
32
  autoload :Completer, "ufo/completer"
32
33
  autoload :Upgrade3, "ufo/upgrade3"
34
+ autoload :Upgrade33_to_34, "ufo/upgrade33_to_34"
33
35
 
34
36
  extend Core
35
37
  end
@@ -77,9 +77,9 @@ module Ufo
77
77
  desc "task TASK_DEFINITION", "Run a one-time task."
78
78
  long_desc Help.text(:task)
79
79
  option :docker, type: :boolean, desc: "Enable docker build and push", default: true
80
- option :command, type: :array, desc: "Override the command used for the container"
80
+ option :command, type: :array, aliases: 'c', desc: "Override the command used for the container"
81
81
  def task(task_definition)
82
- Docker::Builder.build(options)
82
+ Docker::Builder.build(options) if @options[:docker]
83
83
  Tasks::Builder.ship(task_definition, options)
84
84
  Task.new(task_definition, options).run
85
85
  end
@@ -111,11 +111,15 @@ module Ufo
111
111
  end
112
112
 
113
113
  desc "upgrade3", "Upgrade from version 2 to 3."
114
- long_desc Help.text("upgrade3")
115
114
  def upgrade3
116
115
  Upgrade3.new(options).run
117
116
  end
118
117
 
118
+ desc "upgrade3_3_to_3_4", "Upgrade from version 3.3 to 3.4"
119
+ def upgrade3_3_to_3_4
120
+ Upgrade33_to_34.new(options).run
121
+ end
122
+
119
123
  desc "version", "Prints version number of installed ufo."
120
124
  def version
121
125
  puts VERSION
@@ -7,10 +7,6 @@ base:
7
7
  # clean_keep: 30
8
8
  # ecr_keep: 30
9
9
  # defaults when an new ECS service is created by ufo ship
10
- new_service:
11
- maximum_percent: 200
12
- minimum_healthy_percent: 100
13
- desired_count: 1
14
10
 
15
11
  development:
16
12
  # cluster: dev
@@ -1,6 +1,6 @@
1
1
  module Ufo
2
2
  class Destroy
3
- include Default
3
+ include Util
4
4
  include AwsService
5
5
 
6
6
  def initialize(service, options={})
@@ -51,7 +51,7 @@ class Ufo::Docker
51
51
 
52
52
  # full_image - does not include the tag
53
53
  def image_name
54
- setting.data["image"]
54
+ settings["image"]
55
55
  end
56
56
 
57
57
  # full_image - includes the tag
@@ -97,10 +97,6 @@ class Ufo::Docker
97
97
  @git_sha.strip!
98
98
  end
99
99
 
100
- def setting
101
- @setting ||= Ufo::Setting.new(Ufo.root)
102
- end
103
-
104
100
  def update_dockerfile
105
101
  dockerfile = Dockerfile.new(full_image_name, @options)
106
102
  dockerfile.update
@@ -1,14 +1,13 @@
1
1
  module Ufo
2
2
  class Docker::Cleaner
3
3
  include Util
4
- include Default
5
4
 
6
5
  def initialize(docker_image_name, options)
7
6
  # docker_image_name does not containg the tag
8
7
  # Example: 123456789.dkr.ecr.us-east-1.amazonaws.com/image
9
8
  @docker_image_name = docker_image_name
10
9
  @options = options
11
- @keep = options[:keep] || setting.data["clean_keep"] || 3
10
+ @keep = options[:keep] || settings["clean_keep"] || 3
12
11
  @tag_prefix = options[:tag_prefix] || "ufo"
13
12
  end
14
13
 
@@ -43,11 +43,7 @@ class Ufo::Docker
43
43
 
44
44
  # full_image - does not include the tag
45
45
  def image_name
46
- setting.data["image"]
47
- end
48
-
49
- def setting
50
- @setting ||= Ufo::Setting.new(Ufo.root)
46
+ settings["image"]
51
47
  end
52
48
  end
53
49
  end
@@ -89,7 +89,7 @@ module Ufo
89
89
  end
90
90
 
91
91
  def helper
92
- Helper.new(@options)
92
+ Helper.new
93
93
  end
94
94
  end
95
95
  end
@@ -8,9 +8,7 @@ module Ufo
8
8
  class DSL
9
9
  # provides some helperally context variables
10
10
  class Helper
11
- def initialize(options={})
12
- @options = options
13
- end
11
+ include Ufo::Util
14
12
 
15
13
  ##############
16
14
  # helper variables
@@ -22,7 +20,8 @@ module Ufo
22
20
  end
23
21
 
24
22
  def full_image_name
25
- Docker::Builder.new(@options).full_image_name
23
+ # Dont need to use @options here. Helps simplify the Helper initialization.
24
+ Docker::Builder.new({}).full_image_name
26
25
  end
27
26
 
28
27
  #############
@@ -64,10 +63,6 @@ module Ufo
64
63
  @current_region ||= `aws configure get region`.strip rescue 'us-east-1'
65
64
  end
66
65
 
67
- def setting
68
- @setting ||= Setting.new(Ufo.root)
69
- end
70
-
71
66
  def parse_for_dockerfile_port(dockerfile_path)
72
67
  lines = IO.read(dockerfile_path).split("\n")
73
68
  expose_line = lines.find { |l| l =~ /^EXPOSE / }
@@ -17,52 +17,14 @@ module Ufo
17
17
  @dsl.helper
18
18
  end
19
19
 
20
- def build
21
- load_variables
22
- instance_eval(&@block)
23
-
24
- hash = assign_instance_variables
25
- RenderMePretty.result(source_path, hash)
26
- end
27
-
28
- def assign_instance_variables
29
- # copy over the instance variables from TaskDefinition scope to RenderMePretty's scope
30
- hash = {}
31
- instance_variables.each do |var|
32
- key = var.to_s.sub('@','') # rid of the leading @
33
- hash[key.to_sym] = instance_variable_get(var)
34
- end
35
- hash
36
- end
37
-
38
- def load_variables
39
- load_variables_file("base")
40
- load_variables_file(Ufo.env)
20
+ def template_scope
21
+ @template_scope ||= Ufo::TemplateScope.new(helper)
41
22
  end
42
23
 
43
- # Load the variables defined in ufo/variables/* to make available in the
44
- # template blocks in ufo/templates/*.
45
- #
46
- # Example:
47
- #
48
- # `ufo/variables/base.rb`:
49
- # @name = "docker-process-name"
50
- # @image = "docker-image-name"
51
- #
52
- # `ufo/templates/main.json.erb`:
53
- # {
54
- # "containerDefinitions": [
55
- # {
56
- # "name": "<%= @name %>",
57
- # "image": "<%= @image %>",
58
- # ....
59
- # }
60
- #
61
- # NOTE: Only able to make instance variables avaialble with instance_eval
62
- # Wasnt able to make local variables available.
63
- def load_variables_file(filename)
64
- path = "#{Ufo.root}/.ufo/variables/#{filename}.rb"
65
- instance_eval(IO.read(path)) if File.exist?(path)
24
+ def build
25
+ instance_eval(&@block)
26
+ vars = template_scope.assign_instance_variables
27
+ RenderMePretty.result(source_path, vars)
66
28
  end
67
29
 
68
30
  # at this point instance_eval has been called and source has possibly been called
@@ -75,7 +37,7 @@ module Ufo
75
37
  if instance_variable_defined?("@#{var}")
76
38
  puts "WARNING: The instance variable @#{var} is already used internally with ufo. Please name you variable another name!"
77
39
  end
78
- instance_variable_set("@#{var}", value)
40
+ template_scope.instance_variable_set("@#{var}", value)
79
41
  end
80
42
  end
81
43
 
@@ -5,15 +5,15 @@ require "json"
5
5
  # ufo ship app-web --cluster prod --noop
6
6
  module Ufo
7
7
  class Ecr::Cleaner
8
+ include Util
8
9
  include AwsService
9
- include Default
10
10
 
11
11
  def initialize(docker_image_name, options={})
12
12
  # docker_image_name does not containg the tag
13
13
  # Example: 123456789.dkr.ecr.us-east-1.amazonaws.com/image
14
14
  @docker_image_name = docker_image_name
15
15
  @options = options
16
- @keep = options[:ecr_keep] || setting.data["ecr_keep"]
16
+ @keep = options[:ecr_keep] || settings["ecr_keep"]
17
17
  @tag_prefix = options[:tag_prefix] || "ufo"
18
18
  end
19
19
 
@@ -7,7 +7,15 @@ The above command does the following:
7
7
  1. register the `.ufo/output/hi-web.json` task definition to ECS untouched.
8
8
  2. deploys it to ECS by updating the service
9
9
 
10
- The `ufo deploy` command does less than the `ufo ship` command. Typically, people use `ufo ship` over the `ufo deploy` command do everything in one step:
10
+ ### ufo tasks build
11
+
12
+ To regenerate a `.ufo/output/hi-web.json` definition:
13
+
14
+ ufo tasks build
15
+
16
+ ### ufo ship
17
+
18
+ The `ufo deploy` command does less than the `ufo ship` command. Normally, it is recommended to use `ufo ship` over the `ufo deploy` command to do everything in one step:
11
19
 
12
20
  1. build the Docker image
13
21
  2. register the ECS task definition
@@ -19,6 +19,12 @@ For this example we will use [tongueroo/hi](https://github.com/tongueroo/hi) whi
19
19
  append .gitignore
20
20
  Starter ufo files created.
21
21
 
22
+ ## More Short Examples
23
+
24
+ ufo init --image httpd --app demo
25
+ ufo init --image 123456789012.dkr.ecr.us-west-2.amazonaws.com/myimage --app demo
26
+ ufo init --image tongueroo/hi --app hi --launch-type fargate --execution-role-arn arn:aws:iam::536766270177:role/ecsTaskExecutionRole
27
+
22
28
  ## Options: app and image
23
29
 
24
30
  The `app` is that application name that you want to show up on the ECS dashboard. It is encouraged to have the app name be a single word.
@@ -46,6 +52,18 @@ The standard directory structure of the `.ufo` folder that was created looks lik
46
52
 
47
53
  For a explanation of the folders and files refer to [Structure]({% link _docs/structure.md %}).
48
54
 
55
+ ## Fargate Support
56
+
57
+ For ECS Fargate, the ECS task definition structure is a bit different. To initialize a project to support Fargate use the `--launch-type fargate` option. You'll be prompted for a execution role arn. This value gets added to the generated `.ufo/variables/base.rb` and used in the `.ufo/templates/main.json.erb`.
58
+
59
+ ufo init --image tongueroo/hi --app hi --force --launch-type fargate
60
+
61
+ You can also generate the init ufo files and bypass the prompt by providing the `----execution-role-arn` option upfront.
62
+
63
+ ufo init --image tongueroo/hi --app hi --force --launch-type fargate --execution-role-arn arn:aws:iam::536766270177:role/ecsTaskExecutionRole
64
+
65
+ Important: You will need to adjust adjust the generated `.ufo/params.yml` and set the subnet and security_group values which are required for Fargate.
66
+
49
67
  ## Custom Templates
50
68
 
51
69
  If you would like the `ufo init` command to use your own custom templates, you can achieve this with the `--template` and `--template-mode` options. Example:
@@ -1,10 +1,10 @@
1
1
  ## Examples
2
2
 
3
- To run a one time task with ECS:
3
+ You can use the `--command` or `-c` option to override the Docker container command.
4
4
 
5
- ufo task hi-migrate
5
+ ufo task hi-migrate # default command
6
+ ufo task hi-web --command bin/migrate
7
+ ufo task hi-web --command bin/with_env bundle exec rake db:migrate:redo VERSION=xxx
8
+ ufo task hi-web -c uptime
9
+ ufo task hi-web -c pwd
6
10
 
7
- You can also override the command used by the Docker container in the task definitions via command.
8
-
9
- ufo task hi-web --command bin/migrate
10
- ufo task hi-web --command bin/with_env bundle exec rake db:migrate:redo VERSION=xxx
@@ -9,6 +9,8 @@ module Ufo
9
9
  [:force, type: :boolean, desc: "Bypass overwrite are you sure prompt for existing files."],
10
10
  [:image, required: true, desc: "Docker image name without the tag. Example: tongueroo/hi. Configures ufo/settings.yml"],
11
11
  [:app, required: true, desc: "App name. Preferably one word. Used in the generated ufo/task_definitions.rb."],
12
+ [:launch_type, default: "ec2", desc: "ec2 or fargate."],
13
+ [:execution_role_arn, desc: "execution role arn used by tasks, required for fargate."],
12
14
  [:template, desc: "Custom template to use."],
13
15
  [:template_mode, desc: "Template mode: replace or additive."],
14
16
  ]
@@ -50,11 +52,16 @@ module Ufo
50
52
  # map variables
51
53
  @app = options[:app]
52
54
  @image = options[:image]
55
+ @execution_role_arn_input = get_execution_role_arn_input
53
56
  # copy the files
54
57
  puts "Setting up ufo project..."
58
+ directory ".", exclude_pattern: /(\.git|templates)/
55
59
 
56
- # directory ".ufo", ".ufo"
57
- directory ".", exclude_pattern: /\.git/
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
58
65
  end
59
66
 
60
67
  def upsert_gitignore
@@ -0,0 +1,24 @@
1
+ require 'yaml'
2
+ require 'memoist'
3
+
4
+ module Ufo
5
+ class Param
6
+ extend Memoist
7
+
8
+ def initialize
9
+ @params_path = "#{Ufo.root}/.ufo/params.yml"
10
+ end
11
+
12
+ def helper
13
+ dsl = DSL.new("#{Ufo.root}/.ufo/task_definitions.rb", quiet: true, mute: true)
14
+ dsl.helper
15
+ end
16
+
17
+ def data
18
+ vars = Ufo::TemplateScope.new(helper).assign_instance_variables
19
+ result = RenderMePretty.result(@params_path, vars)
20
+ YAML.load(result)
21
+ end
22
+ memoize :data
23
+ end
24
+ end
@@ -1,6 +1,6 @@
1
1
  module Ufo
2
2
  class Scale
3
- include Default
3
+ include Util
4
4
  include AwsService
5
5
 
6
6
  def initialize(service, count, options={})
@@ -11,6 +11,20 @@ module Ufo
11
11
  end
12
12
 
13
13
  private
14
+ def get_execution_role_arn_input
15
+ return @execution_role_arn if @execution_role_arn
16
+
17
+ if @options[:execution_role_arn]
18
+ @execution_role_arn = @options[:execution_role_arn]
19
+ return @execution_role_arn
20
+ end
21
+
22
+ return unless @options[:launch_type] == "fargate"
23
+ # execution role arn required for fargate
24
+ print "Please provide a execution role arn role for the ecs task: "
25
+ @execution_role_arn = $stdin.gets.strip
26
+ end
27
+
14
28
  def override_source_paths(*paths)
15
29
  # Using string with instance_eval because block doesnt have access to
16
30
  # path at runtime.
@@ -5,7 +5,6 @@ module Ufo
5
5
  class ShipmentOverridden < UfoError; end
6
6
 
7
7
  class Ship
8
- include Default
9
8
  include AwsService
10
9
  include Util
11
10
 
@@ -209,16 +208,14 @@ module Ufo
209
208
  options = {
210
209
  cluster: @cluster,
211
210
  service_name: @service,
212
- desired_count: default_desired_count,
213
- deployment_configuration: {
214
- maximum_percent: default_maximum_percent,
215
- minimum_healthy_percent: default_minimum_healthy_percent
216
- },
217
211
  task_definition: @task_definition
218
212
  }
213
+ options = options.merge(default_params[:create_service])
219
214
  unless target_group.nil? || target_group.empty?
220
215
  add_load_balancer!(container, options, target_group)
221
216
  end
217
+ puts "Creating ECS service with params:"
218
+ display_params(options)
222
219
  response = ecs.create_service(options)
223
220
  service = response.service # must set service here since this might never be called if @wait_for_deployment is false
224
221
  end
@@ -248,6 +245,9 @@ module Ufo
248
245
  service: ecs_service.service_arn, # can use the service name also since it is unique
249
246
  task_definition: @task_definition
250
247
  }
248
+ params = params.merge(default_params[:update_service] || {})
249
+ puts "Updating ECS service with params:"
250
+ display_params(params)
251
251
  response = ecs.update_service(params)
252
252
  service = response.service # must set service here since this might never be called if @wait_for_deployment is false
253
253
  end