ufo 6.2.0 → 6.2.1
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/ufo/cli/ps/errors.rb +40 -0
- data/lib/ufo/task_definition/helpers/{core.rb → docker.rb} +9 -24
- data/lib/ufo/task_definition/helpers/{aws_helper.rb → vars/aws_helper.rb} +2 -1
- data/lib/ufo/task_definition/helpers/vars/builder.rb +124 -0
- data/lib/ufo/task_definition/helpers/vars.rb +11 -114
- data/lib/ufo/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 19359c25a4a47a3a997d9a2ad481b2dcb7a1b134474cb8c1acb83b8b2a370815
|
4
|
+
data.tar.gz: e6f4b287dfa7c1a46a9aaac910718ea39e5d4b6170d937a513ecc967ef21bffd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c718937b596ec38c56d997d6e03e6320ca2b556c595fdb0a430b883ad36c0ae96d3f9c6226d912c957b0168d8d820ea753e9ce0ee0f80e702bad3dea106ea893
|
7
|
+
data.tar.gz: f22ffd461ba1992baf9d6f07c9315ff4ed231386663a3fdee77a876effc36ae37120ebc4a9651cf467df104a23409bb86994c947f73c55687a55a39254208808
|
data/CHANGELOG.md
CHANGED
@@ -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
|
+
## [6.2.1] - 2022-03-16
|
7
|
+
- [#153](https://github.com/tongueroo/ufo/pull/153) dockerfile_port also consider Dockerfile.base
|
8
|
+
- [#154](https://github.com/tongueroo/ufo/pull/154) report wrong vpc config errors to user
|
9
|
+
|
6
10
|
## [6.2.0] - 2022-03-16
|
7
11
|
- [#152](https://github.com/tongueroo/ufo/pull/152) ufo docker base: s3 storage support
|
8
12
|
|
data/lib/ufo/cli/ps/errors.rb
CHANGED
@@ -15,6 +15,7 @@ class Ufo::CLI::Ps
|
|
15
15
|
scale
|
16
16
|
target_group
|
17
17
|
deployment_configuration
|
18
|
+
wrong_vpc
|
18
19
|
catchall
|
19
20
|
end
|
20
21
|
|
@@ -86,6 +87,45 @@ class Ufo::CLI::Ps
|
|
86
87
|
EOL
|
87
88
|
end
|
88
89
|
|
90
|
+
# To reproduce #1
|
91
|
+
#
|
92
|
+
# 1. Deploy to with settings where ECS cluster is in custom VPC successfully
|
93
|
+
# 2. Deploy again. Accidentally with default VPC settings <= Reproduction
|
94
|
+
#
|
95
|
+
# This will produce a CloudFormation stack failure
|
96
|
+
#
|
97
|
+
# > All subnets must belong to the same VPC: 'vpc-11111111' (Service: AmazonElasticLoadBalancing; Status Code: 400; Error Code: InvalidConfigurationRequest; Request ID: b8c683ca-4c6d-4bf9-bf9b-3eb468fa9ea9; Proxy: null)
|
98
|
+
#
|
99
|
+
# So it's not actually an ECS failure and is caught early on. Notiing it for posterity.
|
100
|
+
#
|
101
|
+
# To reproduce #2
|
102
|
+
#
|
103
|
+
# Deploy to default VPC. Even though ECS cluster is running on a custom VPC <= Reproduction
|
104
|
+
#
|
105
|
+
# This reproduces:
|
106
|
+
#
|
107
|
+
# > ERROR: (service demo-web-dev-EcsService-RkMBAhHBfx9A) failed to register targets in (target-group arn:aws:elasticloadbalancing:us-west-2:111111111111:targetgroup/demo-Targe-1HEN2QPS5LO9B/0c69c3eb5aa23bc9) with (error The following targets are not in the target group VPC 'vpc-11111111': 'i-11111111111111111')
|
108
|
+
#
|
109
|
+
# The first deploy suceeeds because CloudFormation doesn't check on the ECS service as much here.
|
110
|
+
# ECS does report the error though.
|
111
|
+
#
|
112
|
+
def wrong_vpc
|
113
|
+
error_event = recent_events.find do |e|
|
114
|
+
e.message =~ /targets are not in the target group VPC/ ||
|
115
|
+
e.message =~ /All subnets must belong to the same VPC/
|
116
|
+
end
|
117
|
+
return unless error_event
|
118
|
+
|
119
|
+
logger.info "ERROR: VPC Configuration error".color(:red)
|
120
|
+
logger.info error_event.message.color(:red)
|
121
|
+
logger.info <<~EOL
|
122
|
+
It seems like the ECS Service was deployed to an ECS Cluster running on
|
123
|
+
a different VPC than what's the ECS Service is configured with.
|
124
|
+
|
125
|
+
See: https://ufoships.com/docs/debug/vpc-subnets/
|
126
|
+
EOL
|
127
|
+
end
|
128
|
+
|
89
129
|
# Example:
|
90
130
|
# (service app1-web-dev-EcsService-8FMliG8m6M2p) was unable to stop or start tasks during a deployment because of the service deployment configuration. Update the minimumHealthyPercent or maximumPercent value and try again.
|
91
131
|
def catchall
|
@@ -4,13 +4,16 @@
|
|
4
4
|
# * dockerfile_port - Exposed port in the Dockerfile. Only supports one exposed port, the first one that is encountered.
|
5
5
|
#
|
6
6
|
module Ufo::TaskDefinition::Helpers
|
7
|
-
module
|
8
|
-
extend Memoist
|
9
|
-
|
7
|
+
module Docker
|
10
8
|
def dockerfile_port
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
if File.exist?("Dockerfile")
|
10
|
+
port = parse_for_dockerfile_port("Dockerfile")
|
11
|
+
return port if port
|
12
|
+
end
|
13
|
+
|
14
|
+
# Also consider EXPOSE in Dockerfile.base
|
15
|
+
if File.exist?("Dockerfile.base")
|
16
|
+
parse_for_dockerfile_port("Dockerfile.base")
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
@@ -19,24 +22,6 @@ module Ufo::TaskDefinition::Helpers
|
|
19
22
|
Ufo::Docker::Builder.new({}).docker_image
|
20
23
|
end
|
21
24
|
|
22
|
-
def env(text)
|
23
|
-
Vars.new(text: text).env
|
24
|
-
end
|
25
|
-
alias_method :env_vars, :env
|
26
|
-
alias_method :environment, :env
|
27
|
-
|
28
|
-
def env_file(path)
|
29
|
-
Vars.new(file: path).env
|
30
|
-
end
|
31
|
-
|
32
|
-
def secrets(text)
|
33
|
-
Vars.new(text: text).secrets
|
34
|
-
end
|
35
|
-
|
36
|
-
def secrets_file(path)
|
37
|
-
Vars.new(file: path).secrets
|
38
|
-
end
|
39
|
-
|
40
25
|
def parse_for_dockerfile_port(dockerfile_path)
|
41
26
|
lines = IO.read(dockerfile_path).split("\n")
|
42
27
|
expose_line = lines.find { |l| l =~ /^EXPOSE / }
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require "aws_data"
|
2
|
+
|
3
|
+
module Ufo::TaskDefinition::Helpers::Vars
|
4
|
+
class Builder
|
5
|
+
extend Memoist
|
6
|
+
include AwsHelper
|
7
|
+
include Ufo::Concerns::Names
|
8
|
+
include Ufo::Utils::Pretty
|
9
|
+
include Ufo::Config::CallableOption::Concern
|
10
|
+
|
11
|
+
def initialize(options={})
|
12
|
+
# use either file or text. text takes higher precedence
|
13
|
+
@file = options[:file]
|
14
|
+
@text = options[:text]
|
15
|
+
end
|
16
|
+
|
17
|
+
def content
|
18
|
+
@text || read(@file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def read(path)
|
22
|
+
full_path = "#{Ufo.root}/#{path}"
|
23
|
+
unless File.exist?(full_path)
|
24
|
+
puts "The #{pretty_path(full_path)} env file could not be found. Are you sure it exists?"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
IO.read(full_path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def env
|
31
|
+
lines = filtered_lines(content)
|
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
|
42
|
+
end
|
43
|
+
|
44
|
+
def secrets
|
45
|
+
secrets = env
|
46
|
+
secrets.map do |item|
|
47
|
+
value = item.delete(:value)
|
48
|
+
arn = normalize_to_arn(item[:name], value)
|
49
|
+
value = expansion(arn)
|
50
|
+
value = value.sub('parameter//','parameter/') # auto fix accidental leading slash for user
|
51
|
+
item[:valueFrom] = value
|
52
|
+
end
|
53
|
+
secrets
|
54
|
+
end
|
55
|
+
|
56
|
+
def normalize_to_arn(name, value)
|
57
|
+
case value
|
58
|
+
when /^ssm:/i
|
59
|
+
value.sub(/^ssm:/i, "arn:aws:ssm:#{region}:#{account}:parameter/")
|
60
|
+
when /^secretsmanager:/i
|
61
|
+
value.sub(/^secretsmanager:/i, "arn:aws:secretsmanager:#{region}:#{account}:secret:")
|
62
|
+
when '' # blank string will mean use convention
|
63
|
+
conventional_pattern(name, value)
|
64
|
+
else
|
65
|
+
value # assume full arn has been passed
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
|
70
|
+
# arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
|
71
|
+
def expansion(arn)
|
72
|
+
# performance improvement only run names.expansion on the name portion
|
73
|
+
md = arn.match(/(.*:)(parameter\/|secret:)(.*)/)
|
74
|
+
prefix, type, name = md[1], md[2], md[3]
|
75
|
+
expanded_name = names.expansion(name, dasherize: false) # dasherize: false. dont turn SECRET_NAME => SECRET-NAME
|
76
|
+
"#{prefix}#{type}#{expanded_name}"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Examples with config.secrets.provider = "ssm"
|
80
|
+
#
|
81
|
+
# .secrets
|
82
|
+
#
|
83
|
+
# DB_NAME
|
84
|
+
#
|
85
|
+
# Results
|
86
|
+
#
|
87
|
+
# DB_NAME=:APP/:ENV/:SECRET_NAME # expansion will use => demo/dev/DB_NAME
|
88
|
+
#
|
89
|
+
def conventional_pattern(name, value)
|
90
|
+
secrets = Ufo.config.secrets
|
91
|
+
provider = secrets.provider # ssm or secretsmanager
|
92
|
+
namespace = provider == "ssm" ? "parameter/" : "secret:"
|
93
|
+
|
94
|
+
config_name = "secrets.pattern.#{provider}"
|
95
|
+
pattern = callable_option(
|
96
|
+
config_name: config_name, # Ufo.config.names.stack => :APP-:ROLE-:ENV => demo-web-dev
|
97
|
+
passed_args: [self],
|
98
|
+
)
|
99
|
+
# replace :SECRET_NAME since names expand doesnt know how to nor do we want to add logic there
|
100
|
+
pattern = pattern.sub(':SECRET_NAME', name)
|
101
|
+
"arn:aws:#{provider}:#{region}:#{account}:#{namespace}#{pattern}"
|
102
|
+
end
|
103
|
+
|
104
|
+
def remove_surrounding_quotes(s)
|
105
|
+
if s =~ /^"/ && s =~ /"$/
|
106
|
+
s.sub(/^["]/, '').gsub(/["]$/,'') # remove surrounding double quotes
|
107
|
+
elsif s =~ /^'/ && s =~ /'$/
|
108
|
+
s.sub(/^[']/, '').gsub(/[']$/,'') # remove surrounding single quotes
|
109
|
+
else
|
110
|
+
s
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def filtered_lines(content)
|
115
|
+
lines = content.split("\n")
|
116
|
+
# remove comment at the end of the line
|
117
|
+
lines.map! { |l| l.sub(/\s+#.*/,'').strip }
|
118
|
+
# filter out commented lines
|
119
|
+
lines = lines.reject { |l| l =~ /(^|\s)#/i }
|
120
|
+
# filter out empty lines
|
121
|
+
lines = lines.reject { |l| l.strip.empty? }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -1,124 +1,21 @@
|
|
1
|
-
require "aws_data"
|
2
|
-
|
3
1
|
module Ufo::TaskDefinition::Helpers
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
include Ufo::Concerns::Names
|
8
|
-
include Ufo::Utils::Pretty
|
9
|
-
include Ufo::Config::CallableOption::Concern
|
10
|
-
|
11
|
-
def initialize(options={})
|
12
|
-
# use either file or text. text takes higher precedence
|
13
|
-
@file = options[:file]
|
14
|
-
@text = options[:text]
|
15
|
-
end
|
16
|
-
|
17
|
-
def content
|
18
|
-
@text || read(@file)
|
19
|
-
end
|
20
|
-
|
21
|
-
def read(path)
|
22
|
-
full_path = "#{Ufo.root}/#{path}"
|
23
|
-
unless File.exist?(full_path)
|
24
|
-
puts "The #{pretty_path(full_path)} env file could not be found. Are you sure it exists?"
|
25
|
-
exit 1
|
26
|
-
end
|
27
|
-
IO.read(full_path)
|
28
|
-
end
|
29
|
-
|
30
|
-
def env
|
31
|
-
lines = filtered_lines(content)
|
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
|
2
|
+
module Vars
|
3
|
+
def env(text)
|
4
|
+
Builder.new(text: text).env
|
42
5
|
end
|
6
|
+
alias_method :env_vars, :env
|
7
|
+
alias_method :environment, :env
|
43
8
|
|
44
|
-
def
|
45
|
-
|
46
|
-
secrets.map do |item|
|
47
|
-
value = item.delete(:value)
|
48
|
-
arn = normalize_to_arn(item[:name], value)
|
49
|
-
value = expansion(arn)
|
50
|
-
value = value.sub('parameter//','parameter/') # auto fix accidental leading slash for user
|
51
|
-
item[:valueFrom] = value
|
52
|
-
end
|
53
|
-
secrets
|
54
|
-
end
|
55
|
-
|
56
|
-
def normalize_to_arn(name, value)
|
57
|
-
case value
|
58
|
-
when /^ssm:/i
|
59
|
-
value.sub(/^ssm:/i, "arn:aws:ssm:#{region}:#{account}:parameter/")
|
60
|
-
when /^secretsmanager:/i
|
61
|
-
value.sub(/^secretsmanager:/i, "arn:aws:secretsmanager:#{region}:#{account}:secret:")
|
62
|
-
when '' # blank string will mean use convention
|
63
|
-
conventional_pattern(name, value)
|
64
|
-
else
|
65
|
-
value # assume full arn has been passed
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
|
70
|
-
# arn:aws:ssm:us-west-2:111111111111:parameter/demo/dev/DB-NAME
|
71
|
-
def expansion(arn)
|
72
|
-
# performance improvement only run names.expansion on the name portion
|
73
|
-
md = arn.match(/(.*:)(parameter\/|secret:)(.*)/)
|
74
|
-
prefix, type, name = md[1], md[2], md[3]
|
75
|
-
expanded_name = names.expansion(name, dasherize: false) # dasherize: false. dont turn SECRET_NAME => SECRET-NAME
|
76
|
-
"#{prefix}#{type}#{expanded_name}"
|
77
|
-
end
|
78
|
-
|
79
|
-
# Examples with config.secrets.provider = "ssm"
|
80
|
-
#
|
81
|
-
# .secrets
|
82
|
-
#
|
83
|
-
# DB_NAME
|
84
|
-
#
|
85
|
-
# Results
|
86
|
-
#
|
87
|
-
# DB_NAME=:APP/:ENV/:SECRET_NAME # expansion will use => demo/dev/DB_NAME
|
88
|
-
#
|
89
|
-
def conventional_pattern(name, value)
|
90
|
-
secrets = Ufo.config.secrets
|
91
|
-
provider = secrets.provider # ssm or secretsmanager
|
92
|
-
namespace = provider == "ssm" ? "parameter/" : "secret:"
|
93
|
-
|
94
|
-
config_name = "secrets.pattern.#{provider}"
|
95
|
-
pattern = callable_option(
|
96
|
-
config_name: config_name, # Ufo.config.names.stack => :APP-:ROLE-:ENV => demo-web-dev
|
97
|
-
passed_args: [self],
|
98
|
-
)
|
99
|
-
# replace :SECRET_NAME since names expand doesnt know how to nor do we want to add logic there
|
100
|
-
pattern = pattern.sub(':SECRET_NAME', name)
|
101
|
-
"arn:aws:#{provider}:#{region}:#{account}:#{namespace}#{pattern}"
|
9
|
+
def env_file(path)
|
10
|
+
Builder.new(file: path).env
|
102
11
|
end
|
103
12
|
|
104
|
-
def
|
105
|
-
|
106
|
-
s.sub(/^["]/, '').gsub(/["]$/,'') # remove surrounding double quotes
|
107
|
-
elsif s =~ /^'/ && s =~ /'$/
|
108
|
-
s.sub(/^[']/, '').gsub(/[']$/,'') # remove surrounding single quotes
|
109
|
-
else
|
110
|
-
s
|
111
|
-
end
|
13
|
+
def secrets(text)
|
14
|
+
Builder.new(text: text).secrets
|
112
15
|
end
|
113
16
|
|
114
|
-
def
|
115
|
-
|
116
|
-
# remove comment at the end of the line
|
117
|
-
lines.map! { |l| l.sub(/\s+#.*/,'').strip }
|
118
|
-
# filter out commented lines
|
119
|
-
lines = lines.reject { |l| l =~ /(^|\s)#/i }
|
120
|
-
# filter out empty lines
|
121
|
-
lines = lines.reject { |l| l.strip.empty? }
|
17
|
+
def secrets_file(path)
|
18
|
+
Builder.new(file: path).secrets
|
122
19
|
end
|
123
20
|
end
|
124
21
|
end
|
data/lib/ufo/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ufo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.2.
|
4
|
+
version: 6.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tung Nguyen
|
@@ -629,14 +629,15 @@ files:
|
|
629
629
|
- lib/ufo/task_definition/erb/yaml.rb
|
630
630
|
- lib/ufo/task_definition/helpers.rb
|
631
631
|
- lib/ufo/task_definition/helpers/acm.rb
|
632
|
-
- lib/ufo/task_definition/helpers/
|
633
|
-
- lib/ufo/task_definition/helpers/core.rb
|
632
|
+
- lib/ufo/task_definition/helpers/docker.rb
|
634
633
|
- lib/ufo/task_definition/helpers/ecr.rb
|
635
634
|
- lib/ufo/task_definition/helpers/expansion.rb
|
636
635
|
- lib/ufo/task_definition/helpers/ssm.rb
|
637
636
|
- lib/ufo/task_definition/helpers/ssm/fetcher.rb
|
638
637
|
- lib/ufo/task_definition/helpers/stack_output.rb
|
639
638
|
- lib/ufo/task_definition/helpers/vars.rb
|
639
|
+
- lib/ufo/task_definition/helpers/vars/aws_helper.rb
|
640
|
+
- lib/ufo/task_definition/helpers/vars/builder.rb
|
640
641
|
- lib/ufo/task_definition/helpers/vpc.rb
|
641
642
|
- lib/ufo/task_definition/helpers/waf.rb
|
642
643
|
- lib/ufo/upgrade/params.yml
|