ufo 4.6.1 → 5.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/docs/_docs/conventions.md +1 -1
- data/docs/_docs/extras/codebuild-iam-role.md +1 -1
- data/docs/_docs/extras/dockerfile-erb.md +1 -1
- data/docs/_docs/extras/ecs-network-mode.md +1 -1
- data/docs/_docs/extras/load-balancer.md +1 -1
- data/docs/_docs/extras/minimal-deploy-iam.md +1 -1
- data/docs/_docs/extras/notification-arns.md +21 -0
- data/docs/_docs/extras/redirection-support.md +9 -9
- data/docs/_docs/extras/route53-support.md +4 -4
- data/docs/_docs/extras/security-groups.md +1 -1
- data/docs/_docs/extras/ssl-support.md +5 -5
- data/docs/_docs/faq.md +1 -1
- data/docs/_docs/helpers.md +7 -5
- data/docs/_docs/iam-roles.md +112 -0
- data/docs/_docs/install.md +0 -10
- data/docs/_docs/more/auto-completion.md +1 -1
- data/docs/_docs/more/automated-cleanup.md +1 -1
- data/docs/_docs/more/customize-cloudformation.md +1 -1
- data/docs/_docs/more/migrations.md +1 -1
- data/docs/_docs/more/run-in-pieces.md +1 -1
- data/docs/_docs/more/single-task.md +1 -1
- data/docs/_docs/more/stuck-cloudformation.md +1 -1
- data/docs/_docs/more/why-cloudformation.md +1 -1
- data/docs/_docs/next-steps.md +1 -1
- data/docs/_docs/quick-start-ec2.md +1 -0
- data/docs/_docs/secrets.md +135 -0
- data/docs/_docs/settings.md +10 -9
- data/docs/_docs/settings/cluster.md +7 -13
- data/docs/_docs/settings/manage-security-groups.md +24 -0
- data/docs/_docs/settings/network.md +11 -1
- data/docs/_docs/structure.md +10 -9
- data/docs/_docs/tutorial-ufo-init.md +1 -7
- data/docs/_docs/ufo-current.md +1 -1
- data/docs/_docs/ufo-env-extra.md +1 -1
- data/docs/_docs/ufo-env.md +3 -5
- data/docs/_docs/ufo-logs.md +1 -2
- data/docs/_docs/ufo-task-params.md +1 -1
- data/docs/_docs/upgrading.md +1 -1
- data/docs/_docs/upgrading/upgrade4.5.md +2 -2
- data/docs/_docs/upgrading/upgrade4.md +2 -2
- data/docs/_docs/upgrading/upgrade5.md +19 -0
- data/docs/_docs/variables.md +1 -1
- data/docs/_includes/cfn-customize.md +4 -4
- data/docs/_includes/subnav.html +3 -0
- data/docs/_reference/ufo-deploy.md +1 -2
- data/docs/_reference/ufo-init.md +15 -16
- data/docs/_reference/ufo-logs.md +1 -1
- data/docs/_reference/ufo-rollback.md +2 -0
- data/docs/_reference/ufo-ship.md +1 -2
- data/docs/_reference/ufo-ships.md +1 -2
- data/docs/_reference/ufo-tasks-build.md +1 -2
- data/docs/articles.md +1 -1
- data/docs/quick-start.md +1 -0
- data/lib/template/.secrets +5 -0
- data/lib/template/.ufo/iam_roles/execution_role.rb +7 -0
- data/lib/template/.ufo/iam_roles/task_role.rb +21 -0
- data/lib/template/.ufo/settings.yml.tt +1 -0
- data/lib/template/.ufo/settings/cfn/default.yml.tt +27 -27
- data/lib/template/.ufo/settings/network/default.yml.tt +9 -0
- data/lib/template/.ufo/templates/fargate.json.erb +3 -1
- data/lib/template/.ufo/templates/main.json.erb +3 -0
- data/lib/template/.ufo/variables/base.rb.tt +1 -0
- data/lib/ufo.rb +2 -1
- data/lib/ufo/autoloader.rb +9 -0
- data/lib/ufo/cli.rb +3 -2
- data/lib/ufo/command.rb +7 -0
- data/lib/ufo/core.rb +1 -9
- data/lib/ufo/docker/cleaner.rb +1 -1
- data/lib/ufo/dsl.rb +6 -1
- data/lib/ufo/dsl/helper.rb +19 -37
- data/lib/ufo/dsl/helper/vars.rb +97 -0
- data/lib/ufo/dsl/outputter.rb +12 -9
- data/lib/ufo/ecr/auth.rb +10 -21
- data/lib/ufo/help/init.md +1 -1
- data/lib/ufo/init.rb +0 -2
- data/lib/ufo/log_group.rb +1 -0
- data/lib/ufo/role/builder.rb +66 -0
- data/lib/ufo/role/dsl.rb +21 -0
- data/lib/ufo/role/registry.rb +24 -0
- data/lib/ufo/rollback.rb +2 -1
- data/lib/ufo/sequence.rb +0 -16
- data/lib/ufo/setting/profile.rb +11 -7
- data/lib/ufo/setting/security_groups.rb +22 -0
- data/lib/ufo/settings.rb +20 -0
- data/lib/ufo/stack.rb +24 -24
- data/lib/ufo/stack/builder.rb +26 -0
- data/lib/ufo/stack/builder/base.rb +54 -0
- data/lib/ufo/stack/builder/conditions.rb +23 -0
- data/lib/ufo/stack/builder/outputs.rb +24 -0
- data/lib/ufo/stack/builder/parameters.rb +45 -0
- data/lib/ufo/stack/builder/resources.rb +20 -0
- data/lib/ufo/stack/builder/resources/base.rb +4 -0
- data/lib/ufo/stack/builder/resources/dns.rb +17 -0
- data/lib/ufo/stack/builder/resources/ecs.rb +71 -0
- data/lib/ufo/stack/builder/resources/elb.rb +45 -0
- data/lib/ufo/stack/builder/resources/listener.rb +42 -0
- data/lib/ufo/stack/builder/resources/listener_ssl.rb +16 -0
- data/lib/ufo/stack/builder/resources/roles/base.rb +22 -0
- data/lib/ufo/stack/builder/resources/roles/execution_role.rb +4 -0
- data/lib/ufo/stack/builder/resources/roles/task_role.rb +4 -0
- data/lib/ufo/stack/builder/resources/security_group/base.rb +4 -0
- data/lib/ufo/stack/builder/resources/security_group/ecs.rb +44 -0
- data/lib/ufo/stack/builder/resources/security_group/ecs_rule.rb +25 -0
- data/lib/ufo/stack/builder/resources/security_group/elb.rb +57 -0
- data/lib/ufo/stack/builder/resources/target_group.rb +39 -0
- data/lib/ufo/stack/builder/resources/task_definition.rb +24 -0
- data/lib/ufo/stack/builder/resources/task_definition/reconstructor.rb +49 -0
- data/lib/ufo/stack/context.rb +41 -48
- data/lib/ufo/stack/custom_properties.rb +59 -0
- data/lib/ufo/stack/helper.rb +2 -5
- data/lib/ufo/stack/template_body.rb +13 -0
- data/lib/ufo/task.rb +2 -7
- data/lib/ufo/tasks.rb +1 -1
- data/lib/ufo/tasks/builder.rb +0 -1
- data/lib/ufo/template_scope.rb +1 -66
- data/lib/ufo/utils/squeezer.rb +24 -0
- data/lib/ufo/version.rb +1 -1
- data/spec/fixtures/iam_roles/task_role.rb +17 -0
- data/spec/lib/ecr_auth_spec.rb +32 -20
- data/spec/lib/role/builder_spec.rb +67 -0
- data/spec/lib/role/dsl_spec.rb +12 -0
- data/ufo.gemspec +1 -0
- metadata +61 -3
- data/lib/cfn/stack.yml +0 -283
data/lib/ufo/dsl.rb
CHANGED
@@ -2,6 +2,8 @@ require 'ostruct'
|
|
2
2
|
|
3
3
|
module Ufo
|
4
4
|
class DSL
|
5
|
+
extend Memoist
|
6
|
+
|
5
7
|
def initialize(template_definitions_path, options={})
|
6
8
|
@template_definitions_path = template_definitions_path
|
7
9
|
@options = options
|
@@ -85,7 +87,10 @@ module Ufo
|
|
85
87
|
end
|
86
88
|
|
87
89
|
def helper
|
88
|
-
Helper.new
|
90
|
+
helper = Helper.new
|
91
|
+
helper.add_project_helpers
|
92
|
+
helper
|
89
93
|
end
|
94
|
+
memoize :helper
|
90
95
|
end
|
91
96
|
end
|
data/lib/ufo/dsl/helper.rb
CHANGED
@@ -6,11 +6,20 @@
|
|
6
6
|
# Simply aggregates a bunch of variables that is useful for the task_definition.
|
7
7
|
module Ufo
|
8
8
|
class DSL
|
9
|
-
# provides some helperally context variables
|
10
9
|
class Helper
|
11
10
|
include Ufo::Util
|
12
11
|
extend Memoist
|
13
12
|
|
13
|
+
# Add helpers from .ufo/helpers folder
|
14
|
+
def add_project_helpers
|
15
|
+
helpers_dir = "#{Ufo.root}/.ufo/helpers"
|
16
|
+
Dir.glob("#{helpers_dir}/**/*").each do |path|
|
17
|
+
next unless File.file?(path)
|
18
|
+
klass = path.gsub(%r{.*\.ufo/helpers/},'').sub(".rb",'').camelize
|
19
|
+
self.class.send(:include, klass.constantize)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
##############
|
15
24
|
# helper variables
|
16
25
|
def dockerfile_port
|
@@ -27,48 +36,21 @@ module Ufo
|
|
27
36
|
|
28
37
|
#############
|
29
38
|
# helper methods
|
30
|
-
def
|
31
|
-
|
32
|
-
lines.map do |line|
|
33
|
-
key,*value = line.strip.split("=").map do |x|
|
34
|
-
remove_surrounding_quotes(x.strip)
|
35
|
-
end
|
36
|
-
value = value.join('=')
|
37
|
-
{
|
38
|
-
name: key,
|
39
|
-
value: value,
|
40
|
-
}
|
41
|
-
end
|
39
|
+
def env(text)
|
40
|
+
Vars.new(text: text).env
|
42
41
|
end
|
42
|
+
alias_method :env_vars, :env
|
43
43
|
|
44
|
-
def
|
45
|
-
|
46
|
-
s.sub(/^["]/, '').gsub(/["]$/,'') # remove surrounding double quotes
|
47
|
-
elsif s =~ /^'/ && s =~ /'$/
|
48
|
-
s.sub(/^[']/, '').gsub(/[']$/,'') # remove surrounding single quotes
|
49
|
-
else
|
50
|
-
s
|
51
|
-
end
|
44
|
+
def env_file(path)
|
45
|
+
Vars.new(file: path).env
|
52
46
|
end
|
53
47
|
|
54
|
-
def
|
55
|
-
|
56
|
-
# remove comment at the end of the line
|
57
|
-
lines.map! { |l| l.sub(/\s+#.*/,'').strip }
|
58
|
-
# filter out commented lines
|
59
|
-
lines = lines.reject { |l| l =~ /(^|\s)#/i }
|
60
|
-
# filter out empty lines
|
61
|
-
lines = lines.reject { |l| l.strip.empty? }
|
48
|
+
def secrets(text)
|
49
|
+
Vars.new(text: text).secrets
|
62
50
|
end
|
63
51
|
|
64
|
-
def
|
65
|
-
|
66
|
-
unless File.exist?(full_path)
|
67
|
-
puts "The #{full_path} env file could not be found. Are you sure it exists?"
|
68
|
-
exit 1
|
69
|
-
end
|
70
|
-
text = IO.read(full_path)
|
71
|
-
env_vars(text)
|
52
|
+
def secrets_file(path)
|
53
|
+
Vars.new(file: path).secrets
|
72
54
|
end
|
73
55
|
|
74
56
|
def current_region
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require "aws_data"
|
2
|
+
|
3
|
+
class Ufo::DSL::Helper
|
4
|
+
class Vars
|
5
|
+
extend Memoist
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
# use either file or text. text takes higher precedence
|
9
|
+
@file = options[:file]
|
10
|
+
@text = options[:text]
|
11
|
+
end
|
12
|
+
|
13
|
+
def content
|
14
|
+
@text || read(@file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def read(path)
|
18
|
+
full_path = "#{Ufo.root}/#{path}"
|
19
|
+
unless File.exist?(full_path)
|
20
|
+
puts "The #{full_path} env file could not be found. Are you sure it exists?"
|
21
|
+
exit 1
|
22
|
+
end
|
23
|
+
IO.read(full_path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def env
|
27
|
+
lines = filtered_lines(content)
|
28
|
+
lines.map do |line|
|
29
|
+
key,*value = line.strip.split("=").map do |x|
|
30
|
+
remove_surrounding_quotes(x.strip)
|
31
|
+
end
|
32
|
+
value = value.join('=')
|
33
|
+
{
|
34
|
+
name: key,
|
35
|
+
value: value,
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def secrets
|
41
|
+
secrets = env
|
42
|
+
secrets.map do |item|
|
43
|
+
value = item.delete(:value)
|
44
|
+
item[:valueFrom] = substitute(expand_secret(value))
|
45
|
+
end
|
46
|
+
secrets
|
47
|
+
end
|
48
|
+
|
49
|
+
def expand_secret(value)
|
50
|
+
case value
|
51
|
+
when /^ssm:/i
|
52
|
+
value.sub(/^ssm:/i, "arn:aws:ssm:#{region}:#{account}:parameter/")
|
53
|
+
when /^secretsmanager:/i
|
54
|
+
value.sub(/^secretsmanager:/i, "arn:aws:secretsmanager:#{region}:#{account}:secret:")
|
55
|
+
else
|
56
|
+
value # assume full arn has been passed
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def substitute(value)
|
61
|
+
value.gsub(":UFO_ENV", Ufo.env)
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove_surrounding_quotes(s)
|
65
|
+
if s =~ /^"/ && s =~ /"$/
|
66
|
+
s.sub(/^["]/, '').gsub(/["]$/,'') # remove surrounding double quotes
|
67
|
+
elsif s =~ /^'/ && s =~ /'$/
|
68
|
+
s.sub(/^[']/, '').gsub(/[']$/,'') # remove surrounding single quotes
|
69
|
+
else
|
70
|
+
s
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def filtered_lines(content)
|
75
|
+
lines = content.split("\n")
|
76
|
+
# remove comment at the end of the line
|
77
|
+
lines.map! { |l| l.sub(/\s+#.*/,'').strip }
|
78
|
+
# filter out commented lines
|
79
|
+
lines = lines.reject { |l| l =~ /(^|\s)#/i }
|
80
|
+
# filter out empty lines
|
81
|
+
lines = lines.reject { |l| l.strip.empty? }
|
82
|
+
end
|
83
|
+
|
84
|
+
def aws_data
|
85
|
+
AwsData.new
|
86
|
+
end
|
87
|
+
memoize :aws_data
|
88
|
+
|
89
|
+
def region
|
90
|
+
aws_data.region
|
91
|
+
end
|
92
|
+
|
93
|
+
def account
|
94
|
+
aws_data.account
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/ufo/dsl/outputter.rb
CHANGED
@@ -5,7 +5,6 @@ module Ufo
|
|
5
5
|
@name = name
|
6
6
|
@erb_result = erb_result
|
7
7
|
@options = options
|
8
|
-
@pretty = options[:pretty].nil? ? true : options[:pretty]
|
9
8
|
end
|
10
9
|
|
11
10
|
def write
|
@@ -16,25 +15,29 @@ module Ufo
|
|
16
15
|
path = "#{output_path}/#{@name}.json".sub(/^\.\//,'')
|
17
16
|
puts " #{path}" unless @options[:quiet]
|
18
17
|
validate(@erb_result, path)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
File.open(path, 'w') {|f| f.write(
|
18
|
+
data = JSON.parse(@erb_result)
|
19
|
+
override_image(data)
|
20
|
+
json = JSON.pretty_generate(data)
|
21
|
+
File.open(path, 'w') {|f| f.write(json) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def override_image(data)
|
25
|
+
return data unless @options[:image_override]
|
26
|
+
data["containerDefinitions"].each do |container_definition|
|
27
|
+
container_definition["image"] = @options[:image_override]
|
28
|
+
end
|
23
29
|
end
|
24
30
|
|
25
31
|
def validate(json, path)
|
26
32
|
begin
|
27
33
|
JSON.parse(json)
|
28
34
|
rescue JSON::ParserError => e
|
35
|
+
puts "#{e.class}: #{e.message}"
|
29
36
|
puts "Invalid json. Output written to #{path} for debugging".color(:red)
|
30
37
|
File.open(path, 'w') {|f| f.write(json) }
|
31
38
|
exit 1
|
32
39
|
end
|
33
40
|
end
|
34
|
-
|
35
|
-
def output_json(json)
|
36
|
-
@options[:pretty] ? JSON.pretty_generate(JSON.parse(json)) : json
|
37
|
-
end
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|
data/lib/ufo/ecr/auth.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
1
3
|
=begin
|
2
4
|
Normally, you must authorized to AWS ECR to push to their registry with:
|
3
5
|
|
@@ -27,19 +29,15 @@ module Ufo
|
|
27
29
|
return unless ecr_image?
|
28
30
|
|
29
31
|
auth_token = fetch_auth_token
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
username, password = Base64.decode64(auth_token).split(':')
|
33
|
+
|
34
|
+
command = "docker login -u #{username} --password-stdin #{@repo_domain}"
|
35
|
+
puts "=> #{command}".color(:green)
|
36
|
+
*, status = Open3.capture3(command, stdin_data: password)
|
37
|
+
unless status.success?
|
38
|
+
puts "ERROR: The docker failed to login.".color(:red)
|
39
|
+
exit 1
|
35
40
|
end
|
36
|
-
|
37
|
-
# Handle legacy docker clients that still have old format with https://
|
38
|
-
legacy_entry = "https://#{@repo_domain}"
|
39
|
-
data["auths"][legacy_entry] = {auth: auth_token}
|
40
|
-
|
41
|
-
ensure_dotdocker_exists
|
42
|
-
IO.write(docker_config, JSON.pretty_generate(data))
|
43
41
|
end
|
44
42
|
|
45
43
|
def ecr_image?
|
@@ -50,14 +48,5 @@ module Ufo
|
|
50
48
|
ecr.get_authorization_token.authorization_data.first.authorization_token
|
51
49
|
end
|
52
50
|
|
53
|
-
def docker_config
|
54
|
-
"#{ENV['HOME']}/.docker/config.json"
|
55
|
-
end
|
56
|
-
|
57
|
-
def ensure_dotdocker_exists
|
58
|
-
dirname = File.dirname(docker_config)
|
59
|
-
FileUtils.mkdir_p(dirname) unless File.exist?(dirname)
|
60
|
-
end
|
61
|
-
|
62
51
|
end
|
63
52
|
end
|
data/lib/ufo/help/init.md
CHANGED
@@ -39,7 +39,7 @@ The `image` is the base portion of image name that will be pushed to the docker
|
|
39
39
|
|
40
40
|
The generated `tongueroo/demo-ufo:ufo-2018-02-08T21-04-02-3c86158` image name gets pushed to the docker registry.
|
41
41
|
|
42
|
-
The `--vpc-id`
|
42
|
+
The `--vpc-id`, `--ecs-subnets`, and `--elb-subnets` options are optional but very useful. If not specified then ufo will use the default vpc for the network settings like subnets and security groups, which might not be what you want.
|
43
43
|
|
44
44
|
## Directory Structure
|
45
45
|
|
data/lib/ufo/init.rb
CHANGED
@@ -9,7 +9,6 @@ module Ufo
|
|
9
9
|
[:image, required: true, desc: "Docker image name without the tag. Example: tongueroo/demo-ufo. Configures ufo/settings.yml"],
|
10
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."],
|
11
11
|
[:launch_type, default: "ec2", desc: "ec2 or fargate."],
|
12
|
-
[:execution_role_arn, desc: "execution role arn used by tasks, required for fargate."],
|
13
12
|
[:template, desc: "Custom template to use."],
|
14
13
|
[:template_mode, desc: "Template mode: replace or additive."],
|
15
14
|
[:vpc_id, desc: "Vpc id. For settings/network/default.yml."],
|
@@ -56,7 +55,6 @@ module Ufo
|
|
56
55
|
# map variables
|
57
56
|
@app = options[:app] || inferred_app
|
58
57
|
@image = options[:image]
|
59
|
-
@execution_role_arn_input = get_execution_role_arn_input
|
60
58
|
# copy the files
|
61
59
|
puts "Setting up ufo project..."
|
62
60
|
exclude_pattern = File.exist?("#{Ufo.root}/Dockerfile") ?
|
data/lib/ufo/log_group.rb
CHANGED
@@ -11,6 +11,7 @@ module Ufo
|
|
11
11
|
def create
|
12
12
|
puts "Ensuring log group for #{@task_definition.color(:green)} task definition exists"
|
13
13
|
return if @options[:noop]
|
14
|
+
return if @options[:rollback] # dont need to create log group because previously deployed
|
14
15
|
|
15
16
|
Ufo.check_task_definition!(@task_definition)
|
16
17
|
task_def = JSON.load(IO.read(task_def_path))
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Ufo::Role
|
2
|
+
class Builder
|
3
|
+
def initialize(role_type)
|
4
|
+
@role_type = role_type
|
5
|
+
end
|
6
|
+
|
7
|
+
def build
|
8
|
+
resource(policies, managed_policy_arns)
|
9
|
+
end
|
10
|
+
|
11
|
+
def build?
|
12
|
+
!!(policies || managed_policy_arns)
|
13
|
+
end
|
14
|
+
|
15
|
+
def policies
|
16
|
+
items = Registry.policies[@role_type] # Array of Arrays
|
17
|
+
return unless items && !items.empty?
|
18
|
+
|
19
|
+
items.map do |item|
|
20
|
+
policy_name, statements = item # first element has policy name, second element has statements
|
21
|
+
{
|
22
|
+
PolicyName: policy_name,
|
23
|
+
PolicyDocument: {
|
24
|
+
Version: "2012-10-17",
|
25
|
+
Statement: statements
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def managed_policy_arns
|
32
|
+
items = Registry.managed_policies[@role_type] # Array of Arrays
|
33
|
+
return unless items && !items.empty?
|
34
|
+
|
35
|
+
items.map do |item|
|
36
|
+
item.include?('iam::aws:policy') ? item : "arn:aws:iam::aws:policy/#{item}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def resource(policies, managed_policy_arns)
|
41
|
+
properties = {
|
42
|
+
AssumeRolePolicyDocument: {
|
43
|
+
Version: "2012-10-17",
|
44
|
+
Statement: [
|
45
|
+
{
|
46
|
+
Effect: "Allow",
|
47
|
+
Principal: {
|
48
|
+
Service: "ecs-tasks.amazonaws.com"
|
49
|
+
},
|
50
|
+
Action: "sts:AssumeRole"
|
51
|
+
}
|
52
|
+
]
|
53
|
+
},
|
54
|
+
}
|
55
|
+
properties[:Policies] = policies if policies
|
56
|
+
properties[:ManagedPolicyArns] = managed_policy_arns if managed_policy_arns
|
57
|
+
|
58
|
+
attrs = {
|
59
|
+
Type: "AWS::IAM::Role",
|
60
|
+
Properties: properties
|
61
|
+
}
|
62
|
+
|
63
|
+
attrs.deep_stringify_keys
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/ufo/role/dsl.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Ufo::Role
|
2
|
+
class DSL
|
3
|
+
def initialize(path)
|
4
|
+
@path = path # IE: .ufo/iam_roles/task_role.rb
|
5
|
+
end
|
6
|
+
|
7
|
+
def evaluate
|
8
|
+
instance_eval(IO.read(@path), @path)
|
9
|
+
end
|
10
|
+
|
11
|
+
def iam_policy(policy_name, statements)
|
12
|
+
role_type = File.basename(@path).sub('.rb','') # task_role or execution_role
|
13
|
+
Registry.register_policy(role_type, policy_name, statements)
|
14
|
+
end
|
15
|
+
|
16
|
+
def managed_iam_policy(*policies)
|
17
|
+
role_type = File.basename(@path).sub('.rb','') # task_role or execution_role
|
18
|
+
Registry.register_managed_policy(role_type, policies)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module Ufo::Role
|
4
|
+
class Registry
|
5
|
+
class_attribute :policies
|
6
|
+
self.policies = {}
|
7
|
+
class_attribute :managed_policies
|
8
|
+
self.managed_policies = {}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def register_policy(role_type, policy_name, *statements)
|
12
|
+
statements.flatten!
|
13
|
+
self.policies[role_type] ||= Set.new
|
14
|
+
self.policies[role_type].add([policy_name, statements]) # using set so DSL can safely be evaluated multiple times
|
15
|
+
end
|
16
|
+
|
17
|
+
def register_managed_policy(role_type, *policies)
|
18
|
+
policies.flatten!
|
19
|
+
self.managed_policies[role_type] ||= Set.new
|
20
|
+
self.managed_policies[role_type].merge(policies) # using set so DSL can safely be evaluated multiple times
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/ufo/rollback.rb
CHANGED
@@ -3,7 +3,8 @@ module Ufo
|
|
3
3
|
def deploy
|
4
4
|
task_definition = normalize_version(@options[:version])
|
5
5
|
puts "Rolling back ECS service to task definition #{task_definition}"
|
6
|
-
|
6
|
+
|
7
|
+
ship = Ship.new(@service, @options.merge(task_definition: task_definition, rollback: true))
|
7
8
|
ship.deploy
|
8
9
|
end
|
9
10
|
|